Remove first row, modify room list panel.

This commit is contained in:
Black Hat 2018-11-17 00:04:51 +08:00
parent a296fffd91
commit aaae68a5bf
10 changed files with 322 additions and 507 deletions

View File

@ -15,13 +15,6 @@ Drawer {
id: roomDrawer id: roomDrawer
edge: Qt.RightEdge edge: Qt.RightEdge
interactive: false
ToolButton {
contentItem: MaterialIcon { icon: "\ue5c4" }
onClicked: roomDrawer.close()
}
ColumnLayout { ColumnLayout {
anchors.fill: parent anchors.fill: parent

View File

@ -8,14 +8,10 @@ import Spectral.Setting 0.1
import Spectral.Component 2.0 import Spectral.Component 2.0
Rectangle { Item {
color: MSettings.darkTheme ? "#303030" : "#fafafa"
AutoMouseArea { AutoMouseArea {
anchors.fill: parent anchors.fill: parent
hoverEnabled: miniMode
onSecondaryClicked: { onSecondaryClicked: {
roomContextMenu.model = model roomContextMenu.model = model
roomContextMenu.popup() roomContextMenu.popup()
@ -30,9 +26,6 @@ Rectangle {
enteredRoom = currentRoom enteredRoom = currentRoom
} }
} }
ToolTip.visible: miniMode && containsMouse
ToolTip.text: name
} }
Rectangle { Rectangle {

View File

@ -1,15 +1,44 @@
import QtQuick 2.9 import QtQuick 2.9
import QtQuick.Controls 2.2 import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import QtQuick.Controls.Material 2.2
import Spectral.Component 2.0
import Spectral.Menu 2.0
import Spectral 0.1
import Spectral.Setting 0.1
import SortFilterProxyModel 0.2 import SortFilterProxyModel 0.2
RoomListPanelForm { Rectangle {
model: sortedRoomListModel property var controller: null
readonly property var user: controller.connection ? controller.connection.localUser : null
readonly property int filter: 0
property var enteredRoom: null
property alias errorControl: errorControl
signal enterRoom(var room)
signal leaveRoom(var room)
id: root
color: MSettings.darkTheme ? "#303030" : "#FFFFFF"
RoomListModel {
id: roomListModel
connection: controller.connection
onNewMessage: if (!window.active) spectralController.postNotification(roomId, eventId, roomName, senderName, text, icon, iconPath)
}
SortFilterProxyModel { SortFilterProxyModel {
id: sortedRoomListModel id: sortedRoomListModel
sourceModel: listModel sourceModel: roomListModel
proxyRoles: ExpressionRole { proxyRoles: ExpressionRole {
name: "display" name: "display"
@ -53,9 +82,239 @@ RoomListPanelForm {
] ]
} }
Shortcut { Drawer {
sequence: StandardKey.Find width: Math.max(root.width, 360)
onActivated: searchField.forceActiveFocus() height: root.height
id: drawer
edge: Qt.LeftEdge
ColumnLayout {
width: parent.width
spacing: 0
Control {
Layout.fillWidth: true
Layout.preferredHeight: 330
padding: 24
contentItem: ColumnLayout {
spacing: 4
ImageItem {
Layout.preferredWidth: 200
Layout.preferredHeight: 200
Layout.margins: 12
Layout.alignment: Qt.AlignHCenter
source: root.user ? root.user.paintable : null
hint: root.user ? root.user.displayName : "?"
}
Label {
Layout.alignment: Qt.AlignHCenter
text: root.user ? root.user.displayName : "No Name"
color: "white"
font.pointSize: 16.5
}
Label {
Layout.alignment: Qt.AlignHCenter
text: root.user ? root.user.id : "@example:matrix.org"
color: "white"
opacity: 0.7
font.pointSize: 9.75
}
}
background: Rectangle { color: "#455A64" }
}
Repeater {
model: AccountListModel {
controller: spectralController
}
delegate: ItemDelegate {
Layout.fillWidth: true
text: user.displayName
onClicked: controller.connection = connection
}
}
ItemDelegate {
Layout.fillWidth: true
text: "Exit"
onClicked: Qt.quit()
}
}
}
ColumnLayout {
anchors.fill: parent
spacing: 0
Control {
Layout.fillWidth: true
Layout.preferredHeight: 64
topPadding: 12
bottomPadding: 12
leftPadding: 12
rightPadding: 18
contentItem: RowLayout {
ItemDelegate {
Layout.preferredWidth: height
Layout.fillHeight: true
contentItem: MaterialIcon {
icon: searchField.visible ? "\ue5cd" : "\ue8b6"
color: searchField.visible ? "#1D333E" : "#7F7F7F"
}
onClicked: {
if (searchField.visible) searchField.clear()
searchField.visible = !searchField.visible
}
}
AutoTextField {
Layout.fillWidth: true
Layout.fillHeight: true
id: searchField
visible: false
topPadding: 0
bottomPadding: 0
placeholderText: "Search..."
background: Item {}
}
Label {
Layout.fillWidth: true
Layout.fillHeight: true
visible: !searchField.visible
text: root.user ? root.user.displayName : "No Name"
elide: Text.ElideRight
wrapMode: Text.NoWrap
font.pointSize: 12
color: "#7F7F7F"
verticalAlignment: Text.AlignVCenter
}
ImageItem {
Layout.preferredWidth: height
Layout.fillHeight: true
visible: !searchField.visible
source: root.user ? root.user.paintable : null
hint: root.user ? root.user.displayName : "?"
MouseArea {
anchors.fill: parent
onClicked: drawer.open()
}
}
}
}
Control {
property string error: ""
property string detail: ""
Layout.fillWidth: true
id: errorControl
visible: false
topPadding: 16
bottomPadding: 16
leftPadding: 24
rightPadding: 24
contentItem: ColumnLayout {
Label {
Layout.fillWidth: true
text: errorControl.error
font.pointSize: 12
color: "white"
wrapMode: Text.Wrap
}
Label {
Layout.fillWidth: true
text: errorControl.detail
font.pointSize: 10.5
color: "white"
opacity: 0.6
wrapMode: Text.Wrap
}
ItemDelegate {
Layout.preferredHeight: 32
Layout.alignment: Qt.AlignRight
text: "Dismiss"
Material.foreground: "white"
onClicked: errorControl.visible = false
}
}
background: Rectangle { color: "#273338" }
}
AutoListView {
Layout.fillWidth: true
Layout.fillHeight: true
id: listView
spacing: 0
clip: true
model: sortedRoomListModel
boundsBehavior: Flickable.DragOverBounds
ScrollBar.vertical: ScrollBar {}
delegate: RoomListDelegate {
width: parent.width
height: 64
}
section.property: "display"
section.criteria: ViewSection.FullString
section.delegate: Label {
width: parent.width
height: 24
text: section
color: "#5B7480"
leftPadding: 16
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
}
RoomContextMenu {
id: roomContextMenu
}
}
} }
Dialog { Dialog {

View File

@ -1,138 +0,0 @@
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import QtGraphicalEffects 1.0
import QtQuick.Controls.Material 2.2
import QtQml.Models 2.3
import Spectral.Component 2.0
import Spectral.Menu 2.0
import Spectral.Effect 2.0
import Spectral 0.1
import Spectral.Setting 0.1
import SortFilterProxyModel 0.2
import "qrc:/js/util.js" as Util
Rectangle {
property var listModel
property int filter: 0
property var enteredRoom: null
property alias searchField: searchField
property alias model: listView.model
property bool miniMode: width == 64
signal enterRoom(var room)
signal leaveRoom(var room)
color: MSettings.darkTheme ? "#323232" : "#f3f3f3"
Label {
text: miniMode ? "Empty" : "Here? No, not here."
anchors.centerIn: parent
visible: listView.count === 0
}
ColumnLayout {
anchors.fill: parent
spacing: 0
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 40
Layout.margins: 12
color: MSettings.darkTheme ? "#303030" : "#fafafa"
RowLayout {
anchors.fill: parent
spacing: 0
MaterialIcon {
Layout.preferredWidth: height
Layout.fillHeight: true
visible: !miniMode && !searchField.text
icon: "\ue8b6"
color: "grey"
}
ItemDelegate {
Layout.preferredWidth: height
Layout.fillHeight: true
visible: !miniMode && searchField.text
contentItem: MaterialIcon {
icon: "\ue5cd"
color: "grey"
}
onClicked: searchField.text = ""
}
AutoTextField {
Layout.fillWidth: true
Layout.fillHeight: true
id: searchField
topPadding: 0
bottomPadding: 0
placeholderText: "Search..."
background: Item {
}
}
}
}
AutoListView {
Layout.fillWidth: true
Layout.fillHeight: true
id: listView
spacing: 0
clip: true
boundsBehavior: Flickable.DragOverBounds
ScrollBar.vertical: ScrollBar {
}
delegate: RoomListDelegate {
width: parent.width
height: 64
}
section.property: "display"
section.criteria: ViewSection.FullString
section.delegate: Label {
width: parent.width
height: 24
text: section
color: "grey"
leftPadding: miniMode ? undefined : 16
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
horizontalAlignment: miniMode ? Text.AlignHCenter : undefined
}
RoomContextMenu {
id: roomContextMenu
}
}
}
}
/*##^## Designer {
D{i:0;autoSize:true;height:480;width:640}
}
##^##*/

View File

@ -55,7 +55,7 @@ Item {
visible: currentRoom visible: currentRoom
source: "qrc:/assets/img/roompanel.svg" source: "qrc:/assets/img/roompanel.svg"
fillMode: Image.Pad fillMode: Image.PreserveAspectCrop
} }
ColumnLayout { ColumnLayout {

View File

@ -102,14 +102,6 @@ Rectangle {
} }
} }
Rectangle {
width: currentRoom && currentRoom.hasFileUploading ? parent.width * currentRoom.fileUploadingProgress / 100 : 0
height: parent.height
opacity: 0.2
color: Material.accent
}
RowLayout { RowLayout {
anchors.fill: parent anchors.fill: parent
@ -169,6 +161,14 @@ Rectangle {
background: Item { background: Item {
} }
Rectangle {
width: currentRoom && currentRoom.hasFileUploading ? parent.width * currentRoom.fileUploadingProgress / 100 : 0
height: parent.height
opacity: 0.2
color: Material.accent
}
Timer { Timer {
id: timeoutTimer id: timeoutTimer

View File

@ -5,8 +5,10 @@ import QtQuick.Controls.Material 2.2
import Qt.labs.settings 1.0 import Qt.labs.settings 1.0
import Qt.labs.platform 1.0 as Platform import Qt.labs.platform 1.0 as Platform
import Spectral.Panel 2.0
import Spectral.Component 2.0 import Spectral.Component 2.0
import Spectral.Page 2.0 import Spectral.Page 2.0
import Spectral.Effect 2.0
import Spectral 0.1 import Spectral 0.1
import Spectral.Setting 0.1 import Spectral.Setting 0.1
@ -14,8 +16,6 @@ import Spectral.Setting 0.1
import "qrc:/js/util.js" as Util import "qrc:/js/util.js" as Util
ApplicationWindow { ApplicationWindow {
readonly property var currentConnection: accountListView.currentConnection ? accountListView.currentConnection : null
Material.theme: MSettings.darkTheme ? Material.Dark : Material.Light Material.theme: MSettings.darkTheme ? Material.Dark : Material.Light
width: 960 width: 960
@ -52,353 +52,50 @@ ApplicationWindow {
quitOnLastWindowClosed: !MSettings.showTray quitOnLastWindowClosed: !MSettings.showTray
onNotificationClicked: { onNotificationClicked: {
roomPage.enteredRoom = currentConnection.room(roomId) roomPage.enteredRoom = spectralController.connection.room(roomId)
roomPage.goToEvent(eventId) roomPage.goToEvent(eventId)
showWindow() showWindow()
} }
onErrorOccured: { onErrorOccured: {
errorDialog.error = error roomListForm.errorControl.error = error
errorDialog.detail = detail roomListForm.errorControl.detail = detail
errorDialog.open() roomListForm.errorControl.visible = true
} }
onSyncDone: roomListForm.errorControl.visible = false
} }
AccountListModel { SplitView {
id: accountListModel anchors.fill: parent
RoomListPanel {
width: window.width * 0.35
Layout.minimumWidth: 180
id: roomListForm
clip: true
controller: spectralController controller: spectralController
onLeaveRoom: roomForm.saveReadMarker(room)
} }
Dialog { RoomPanel {
property string error
property string detail
x: (window.width - width) / 2
y: (window.height - height) / 2
id: errorDialog
title: error + " Error"
contentItem: Label { text: errorDialog.detail }
}
Component {
id: loginPage
Login { controller: spectralController }
}
Room {
id: roomPage
parent: null
connection: currentConnection
}
Setting {
id: settingPage
parent: null
listModel: accountListModel
}
RowLayout {
anchors.fill: parent
spacing: 0
Rectangle {
Layout.preferredWidth: 64
Layout.fillHeight: true
id: sideNav
color: Material.primary
ColumnLayout {
anchors.fill: parent
spacing: 0
AutoListView {
property var currentConnection: null
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.minimumWidth: 480
id: accountListView id: roomForm
model: accountListModel
spacing: 0
clip: true clip: true
delegate: Column { currentRoom: roomListForm.enteredRoom
property bool expanded: accountListView.currentConnection === connection
width: parent.width
spacing: 0
SideNavButton {
width: parent.width
height: width
selected: stackView.currentItem === page && currentConnection === connection
ImageItem {
anchors.fill: parent
anchors.margins: 12
hint: user.displayName
source: user.paintable
}
highlightColor: Material.accent
page: roomPage
onClicked: {
accountListView.currentConnection = connection
roomPage.filter = 0
}
}
Column {
width: parent.width
height: expanded ? implicitHeight : 0
spacing: 0
clip: true
SideNavButton {
width: parent.width
height: width
MaterialIcon {
anchors.fill: parent
icon: "\ue7f7"
color: "white"
}
onClicked: roomPage.filter = 1
}
SideNavButton {
width: parent.width
height: width
MaterialIcon {
anchors.fill: parent
icon: "\ue7fd"
color: "white"
}
onClicked: roomPage.filter = 2
}
SideNavButton {
width: parent.width
height: width
MaterialIcon {
anchors.fill: parent
icon: "\ue7fb"
color: "white"
}
onClicked: roomPage.filter = 3
}
Behavior on height {
PropertyAnimation { easing.type: Easing.InOutCubic; duration: 200 }
}
}
}
}
SideNavButton {
Layout.fillWidth: true
Layout.preferredHeight: width
MaterialIcon {
anchors.fill: parent
icon: "\ue145"
color: "white"
}
enabled: !addRoomMenu.opened
onClicked: addRoomMenu.popup()
Menu {
id: addRoomMenu
MenuItem {
text:"New Room"
onTriggered: addRoomDialog.open()
Dialog {
id: addRoomDialog
parent: ApplicationWindow.overlay
x: (window.width - width) / 2
y: (window.height - height) / 2
width: 360
title: "New Room"
modal: true
standardButtons: Dialog.Ok | Dialog.Cancel
contentItem: Column {
AutoTextField {
width: parent.width
id: addRoomDialogNameTextField
placeholderText: "Name"
}
AutoTextField {
width: parent.width
id: addRoomDialogTopicTextField
placeholderText: "Topic"
}
}
onAccepted: spectralController.createRoom(currentConnection, addRoomDialogNameTextField.text, addRoomDialogTopicTextField.text)
}
}
MenuItem {
text: "Join Room"
onTriggered: joinRoomDialog.open()
Dialog {
x: (window.width - width) / 2
y: (window.height - height) / 2
width: 360
id: joinRoomDialog
parent: ApplicationWindow.overlay
title: "Input Room Alias or ID"
modal: true
standardButtons: Dialog.Ok | Dialog.Cancel
contentItem: AutoTextField {
id: joinRoomDialogTextField
placeholderText: "#matrix:matrix.org"
}
onAccepted: spectralController.joinRoom(currentConnection, joinRoomDialogTextField.text)
}
}
MenuItem {
text: "Direct Chat"
onTriggered: directChatDialog.open()
Dialog {
x: (window.width - width) / 2
y: (window.height - height) / 2
width: 360
id: directChatDialog
parent: ApplicationWindow.overlay
title: "Input User ID"
modal: true
standardButtons: Dialog.Ok | Dialog.Cancel
contentItem: AutoTextField {
id: directChatDialogTextField
placeholderText: "@bot:matrix.org"
}
onAccepted: spectralController.createDirectChat(currentConnection, directChatDialogTextField.text)
}
}
}
}
SideNavButton {
Layout.fillWidth: true
Layout.preferredHeight: width
MaterialIcon {
anchors.fill: parent
icon: "\ue8b8"
color: "white"
}
page: settingPage
}
SideNavButton {
Layout.fillWidth: true
Layout.preferredHeight: width
MaterialIcon {
anchors.fill: parent
icon: "\ue8ac"
color: "white"
}
onClicked: MSettings.confirmOnExit ? confirmExitDialog.open() : Qt.quit()
Dialog {
x: (window.width - width) / 2
y: (window.height - height) / 2
width: 360
id: confirmExitDialog
parent: ApplicationWindow.overlay
title: "Exit"
modal: true
standardButtons: Dialog.Ok | Dialog.Cancel
contentItem: Column {
Label { text: "Exit?" }
CheckBox {
text: "Do not ask next time"
checked: !MSettings.confirmOnExit
onCheckedChanged: MSettings.confirmOnExit = !checked
}
}
onAccepted: Qt.quit()
}
}
}
}
StackView {
Layout.fillWidth: true
Layout.fillHeight: true
id: stackView
initialItem: roomPage
} }
} }
Binding { Binding {
target: imageProvider target: imageProvider
property: "connection" property: "connection"
value: currentConnection value: spectralController.connection
} }
function showWindow() { function showWindow() {
@ -411,6 +108,10 @@ ApplicationWindow {
window.hide() window.hide()
} }
function showError() {
}
Component.onCompleted: { Component.onCompleted: {
spectralController.initiated.connect(function() { spectralController.initiated.connect(function() {
if (spectralController.accountCount == 0) stackView.push(loginPage) if (spectralController.accountCount == 0) stackView.push(loginPage)

View File

@ -38,7 +38,6 @@
<file>imports/Spectral/Panel/qmldir</file> <file>imports/Spectral/Panel/qmldir</file>
<file>imports/Spectral/Panel/RoomDrawer.qml</file> <file>imports/Spectral/Panel/RoomDrawer.qml</file>
<file>imports/Spectral/Panel/RoomListPanel.qml</file> <file>imports/Spectral/Panel/RoomListPanel.qml</file>
<file>imports/Spectral/Panel/RoomListPanelForm.ui.qml</file>
<file>imports/Spectral/Panel/RoomPanel.qml</file> <file>imports/Spectral/Panel/RoomPanel.qml</file>
<file>imports/Spectral/Panel/RoomPanelForm.ui.qml</file> <file>imports/Spectral/Panel/RoomPanelForm.ui.qml</file>
<file>imports/Spectral/Panel/RoomHeader.qml</file> <file>imports/Spectral/Panel/RoomHeader.qml</file>

View File

@ -75,7 +75,7 @@ void Controller::loginWithCredentials(QString serverAddr, QString user,
}); });
connect(m_connection, &Connection::networkError, connect(m_connection, &Connection::networkError,
[=](QString error, QByteArray detail) { [=](QString error, QByteArray detail) {
emit errorOccured("Network", error); emit errorOccured("Network Error", error);
}); });
connect(m_connection, &Connection::loginError, connect(m_connection, &Connection::loginError,
[=](QString error, QByteArray detail) { [=](QString error, QByteArray detail) {
@ -110,6 +110,7 @@ void Controller::addConnection(Connection* c) {
m_connections.push_back(c); m_connections.push_back(c);
connect(c, &Connection::syncDone, this, [=] { connect(c, &Connection::syncDone, this, [=] {
emit syncDone();
c->sync(30000); c->sync(30000);
static int counter = 0; static int counter = 0;
@ -152,11 +153,12 @@ void Controller::invokeLogin() {
}); });
connect(c, &Connection::networkError, connect(c, &Connection::networkError,
[=](QString error, QByteArray detail) { [=](QString error, QByteArray detail) {
emit errorOccured("Network", error); emit errorOccured("Network Error", error);
}); });
c->connectWithToken(account.userId(), accessToken, account.deviceId()); c->connectWithToken(account.userId(), accessToken, account.deviceId());
} }
} }
if (!m_connections.isEmpty()) setConnection(m_connections[0]);
emit initiated(); emit initiated();
} }
@ -184,7 +186,7 @@ bool Controller::saveAccessToken(const AccountSettings& account,
auto fileDir = QFileInfo(accountTokenFile).dir(); auto fileDir = QFileInfo(accountTokenFile).dir();
if (!((fileDir.exists() || fileDir.mkpath(".")) && if (!((fileDir.exists() || fileDir.mkpath(".")) &&
accountTokenFile.open(QFile::WriteOnly))) { accountTokenFile.open(QFile::WriteOnly))) {
emit errorOccured("Token", "Cannot save access token."); emit errorOccured("I/O Denied", "Cannot save access token.");
} else { } else {
accountTokenFile.write(accessToken); accountTokenFile.write(accessToken);
return true; return true;
@ -227,14 +229,6 @@ void Controller::playAudio(QUrl localFile) {
connect(player, &QMediaPlayer::stateChanged, [=] { player->deleteLater(); }); connect(player, &QMediaPlayer::stateChanged, [=] { player->deleteLater(); });
} }
QColor Controller::color(QString userId) {
return QColor(SettingsGroup("UI/Color").value(userId, "#498882").toString());
}
void Controller::setColor(QString userId, QColor newColor) {
SettingsGroup("UI/Color").setValue(userId, newColor.name());
}
void Controller::postNotification(const QString& roomId, const QString& eventId, void Controller::postNotification(const QString& roomId, const QString& eventId,
const QString& roomName, const QString& roomName,
const QString& senderName, const QString& senderName,

View File

@ -20,6 +20,8 @@ class Controller : public QObject {
connectionDropped) connectionDropped)
Q_PROPERTY(bool quitOnLastWindowClosed READ quitOnLastWindowClosed WRITE Q_PROPERTY(bool quitOnLastWindowClosed READ quitOnLastWindowClosed WRITE
setQuitOnLastWindowClosed NOTIFY quitOnLastWindowClosedChanged) setQuitOnLastWindowClosed NOTIFY quitOnLastWindowClosedChanged)
Q_PROPERTY(Connection* connection READ connection WRITE setConnection NOTIFY
connectionChanged)
public: public:
explicit Controller(QObject* parent = nullptr); explicit Controller(QObject* parent = nullptr);
@ -47,13 +49,23 @@ class Controller : public QObject {
} }
} }
Q_INVOKABLE QColor color(QString userId); Connection* connection() {
Q_INVOKABLE void setColor(QString userId, QColor newColor); if (m_connection.isNull()) return nullptr;
return m_connection;
}
void setConnection(Connection* conn) {
if (!conn) return;
if (conn == m_connection) return;
m_connection = conn;
emit connectionChanged();
}
private: private:
QClipboard* m_clipboard = QApplication::clipboard(); QClipboard* m_clipboard = QApplication::clipboard();
NotificationsManager notificationsManager; NotificationsManager notificationsManager;
QVector<Connection*> m_connections; QVector<Connection*> m_connections;
QPointer<Connection> m_connection;
QByteArray loadAccessToken(const AccountSettings& account); QByteArray loadAccessToken(const AccountSettings& account);
bool saveAccessToken(const AccountSettings& account, bool saveAccessToken(const AccountSettings& account,
@ -67,11 +79,13 @@ class Controller : public QObject {
signals: signals:
void busyChanged(); void busyChanged();
void errorOccured(QString error, QString detail); void errorOccured(QString error, QString detail);
void syncDone();
void connectionAdded(Connection* conn); void connectionAdded(Connection* conn);
void connectionDropped(Connection* conn); void connectionDropped(Connection* conn);
void initiated(); void initiated();
void notificationClicked(const QString roomId, const QString eventId); void notificationClicked(const QString roomId, const QString eventId);
void quitOnLastWindowClosedChanged(); void quitOnLastWindowClosedChanged();
void connectionChanged();
public slots: public slots:
void logout(Connection* conn); void logout(Connection* conn);