Single room list approach, account bar scrolls

This commit is contained in:
miruka 2020-04-29 14:00:02 -04:00
parent 56c09e6b48
commit fcf88209f2
13 changed files with 129 additions and 172 deletions

View File

@ -1,5 +1,7 @@
# TODO # TODO
- rename goto*account → scrollto*account
- account number binds
- update glass theme - update glass theme
- back/front buttons in small window - back/front buttons in small window
- minimum sizes - minimum sizes

View File

@ -871,6 +871,7 @@ class MatrixClient(nio.AsyncClient):
""" """
self.models[self.user_id, "rooms"].pop(room_id, None) self.models[self.user_id, "rooms"].pop(room_id, None)
self.models["every_room"].pop((self.user_id, room_id), None)
self.models.pop((self.user_id, room_id, "events"), None) self.models.pop((self.user_id, room_id, "events"), None)
self.models.pop((self.user_id, room_id, "members"), None) self.models.pop((self.user_id, room_id, "members"), None)
@ -1209,8 +1210,9 @@ class MatrixClient(nio.AsyncClient):
mentions = 0 mentions = 0
unreads = 0 unreads = 0
self.models[self.user_id, "rooms"][room.room_id] = Room( room_item = Room(
id = room.room_id, id = room.room_id,
for_account = self.user_id,
given_name = room.name or "", given_name = room.name or "",
display_name = room.display_name or "", display_name = room.display_name or "",
avatar_url = room.gen_avatar_url or "", avatar_url = room.gen_avatar_url or "",
@ -1244,9 +1246,11 @@ class MatrixClient(nio.AsyncClient):
last_event_date = last_event_date, last_event_date = last_event_date,
mentions = mentions, mentions = mentions,
unreads = unreads, unreads = unreads,
) )
self.models[self.user_id, "rooms"][room.room_id] = room_item
self.models["every_room"][self.user_id, room.room_id] = room_item
# List members that left the room, then remove them from our model # List members that left the room, then remove them from our model
left_the_room = [ left_the_room = [
user_id user_id

View File

@ -40,9 +40,9 @@ class Account(ModelItem):
first_sync_done: bool = False first_sync_done: bool = False
def __lt__(self, other: "Account") -> bool: def __lt__(self, other: "Account") -> bool:
"""Sort by display name or user ID.""" """Sort by user ID."""
name = self.display_name or self.id[1:] name = self.id[1:]
other_name = other.display_name or other.id[1:] other_name = other.id[1:]
return name.lower() < other_name.lower() return name.lower() < other_name.lower()
@ -51,6 +51,7 @@ class Room(ModelItem):
"""A matrix room we are invited to, are or were member of.""" """A matrix room we are invited to, are or were member of."""
id: str = field() id: str = field()
for_account: str = field()
given_name: str = "" given_name: str = ""
display_name: str = "" display_name: str = ""
main_alias: str = "" main_alias: str = ""
@ -90,19 +91,22 @@ class Room(ModelItem):
Invited rooms are first, then joined rooms, then left rooms. Invited rooms are first, then joined rooms, then left rooms.
Within these categories, sort by last event date (room with recent Within these categories, sort by last event date (room with recent
messages are first), then by display names, but messages are first), then by display names, then account, but
keep rooms with mentions on top, followed by rooms with unread events. keep rooms with mentions on top, followed by rooms with unread events.
""" """
# Left rooms may still have an inviter_id, so check left first. # Left rooms may still have an inviter_id, so check left first.
return ( return (
self.for_account,
self.left, self.left,
other.inviter_id, other.inviter_id,
bool(other.mentions), bool(other.mentions),
bool(other.unreads), bool(other.unreads),
other.last_event_date, other.last_event_date,
(self.display_name or self.id).lower(), (self.display_name or self.id).lower(),
) < ( ) < (
other.for_account,
other.left, other.left,
self.inviter_id, self.inviter_id,
bool(self.mentions), bool(self.mentions),

View File

@ -217,7 +217,7 @@ HDrawer {
NumberAnimation { NumberAnimation {
running: doUselessThing running: doUselessThing
target: mainUI.mainPane.mainPaneList target: mainUI.mainPane.roomList
property: "rotation" property: "rotation"
duration: 250 duration: 250
from: 360 from: 360
@ -225,19 +225,4 @@ HDrawer {
loops: Animation.Infinite loops: Animation.Infinite
onStopped: target.rotation = 0 onStopped: target.rotation = 0
} }
NumberAnimation {
running: doUselessThing
target: mainUI.pageLoader
property: "scale"
duration: 250
from: 1
to: -1
onStopped: if (doUselessThing) {
[from, to] = [to, from]
start()
} else {
target.scale = 1
}
}
} }

View File

@ -17,17 +17,19 @@ HTile {
HUserAvatar { HUserAvatar {
id: avatar id: avatar
userId: model.id userId: accountModel.id
displayName: model.display_name displayName: accountModel.display_name
mxc: model.avatar_url mxc: accountModel.avatar_url
radius: 0 radius: 0
} }
TitleLabel { TitleLabel {
text: model.display_name || model.id text: accountModel.display_name || accountModel.id
color: color:
hovered ? hovered ?
utils.nameColor(model.display_name || model.id.substring(1)) : utils.nameColor(
accountModel.display_name || accountModel.id.substring(1),
) :
theme.accountView.account.name theme.accountView.account.name
Behavior on color { HColorAnimation {} } Behavior on color { HColorAnimation {} }
@ -40,7 +42,7 @@ HTile {
backgroundColor: "transparent" backgroundColor: "transparent"
toolTip.text: qsTr("Add new chat") toolTip.text: qsTr("Add new chat")
onClicked: pageLoader.showPage( onClicked: pageLoader.showPage(
"AddChat/AddChat", {userId: model.id}, "AddChat/AddChat", {userId: accountModel.id},
) )
Layout.fillHeight: true Layout.fillHeight: true
@ -59,7 +61,7 @@ HTile {
HMenuItem { HMenuItem {
icon.name: "copy-user-id" icon.name: "copy-user-id"
text: qsTr("Copy user ID") text: qsTr("Copy user ID")
onTriggered: Clipboard.text = model.id onTriggered: Clipboard.text = accountModel.id
} }
HMenuItemPopupSpawner { HMenuItemPopupSpawner {
@ -68,17 +70,18 @@ HTile {
text: qsTr("Sign out") text: qsTr("Sign out")
popup: "Popups/SignOutPopup.qml" popup: "Popups/SignOutPopup.qml"
properties: { "userId": model.id } properties: { "userId": accountModel.id }
} }
} }
onLeftClicked: { onLeftClicked: {
pageLoader.showPage( pageLoader.showPage(
"AccountSettings/AccountSettings", { "userId": model.id } "AccountSettings/AccountSettings", { "userId": accountModel.id }
) )
} }
property var accountModel
property bool isCurrent: false property bool isCurrent: false

View File

@ -1,16 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
import QtQuick 2.12
import ".."
import "../Base"
HSwipeView {
id: swipeView
orientation: Qt.Vertical
Repeater {
model: ModelStore.get("accounts")
AccountView {}
}
}

View File

@ -1,46 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
import QtQuick 2.12
import QtQuick.Layouts 1.12
import ".."
import "../Base"
HLoader {
id: loader
active:
HSwipeView.isCurrentItem ||
HSwipeView.isNextItem ||
HSwipeView.isPreviousItem
readonly property bool isCurrent: HSwipeView.isCurrentItem
sourceComponent: HColumnLayout {
id: column
readonly property QtObject accountModel: model
readonly property alias roomList: roomList
Account {
id: account
isCurrent: loader.isCurrent
Layout.fillWidth: true
}
RoomList {
id: roomList
clip: true
accountModel: column.accountModel
roomPane: swipeView
isCurrent: loader.isCurrent
Layout.fillWidth: true
Layout.fillHeight: true
}
FilterRoomsField {
roomList: roomList
Layout.fillWidth: true
}
}
}

View File

@ -8,21 +8,21 @@ import "../Base"
import "../Base/HTile" import "../Base/HTile"
HColumnLayout { HColumnLayout {
property AccountSwipeView accountSwipeView property RoomList roomList
HButton { HButton {
id: everyRoomButton id: addAccountButton
icon.name: "every-room" icon.name: "add-account"
toolTip.text: qsTr("Every room") toolTip.text: qsTr("Add another account")
backgroundColor: theme.accountsBar.everyRoomButtonBackground backgroundColor: theme.accountsBar.addAccountButtonBackground
// onClicked: pageLoader.showPage("AddAccount/AddAccount") onClicked: pageLoader.showPage("AddAccount/AddAccount")
Layout.preferredHeight: theme.baseElementsHeight Layout.preferredHeight: theme.baseElementsHeight
HShortcut { HShortcut {
sequences: window.settings.keys.showEveryRoom sequences: window.settings.keys.addNewAccount
onActivated: everyRoomButton.clicked() onActivated: addAccountButton.clicked()
} }
} }
@ -30,10 +30,14 @@ HColumnLayout {
id: accountList id: accountList
clip: true clip: true
model: ModelStore.get("accounts") model: ModelStore.get("accounts")
currentIndex: accountSwipeView.currentIndex currentIndex:
roomList.currentIndex === -1 ?
-1 :
model.findIndex(
roomList.model.get(roomList.currentIndex).for_account, -1,
)
highlight: Item { highlight: Item {
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: theme.accountsBar.accountList.account.selectedBackground color: theme.accountsBar.accountList.account.selectedBackground
@ -74,7 +78,7 @@ HColumnLayout {
} }
} }
onLeftClicked: accountSwipeView.currentIndex = model.index onLeftClicked: roomList.goToAccount(model.id)
} }
Layout.fillWidth: true Layout.fillWidth: true
@ -82,12 +86,18 @@ HColumnLayout {
HShortcut { HShortcut {
sequences: window.settings.keys.goToPreviousAccount sequences: window.settings.keys.goToPreviousAccount
onActivated: accountSwipeView.decrementWrapIndex() onActivated: {
accountList.decrementCurrentIndex()
accountList.currentItem.leftClicked()
}
} }
HShortcut { HShortcut {
sequences: window.settings.keys.goToNextAccount sequences: window.settings.keys.goToNextAccount
onActivated: accountSwipeView.incrementWrapIndex() onActivated: {
accountList.incrementCurrentIndex()
accountList.currentItem.leftClicked()
}
} }
Rectangle { Rectangle {
@ -97,21 +107,6 @@ HColumnLayout {
} }
} }
HButton {
id: addAccountButton
icon.name: "add-account"
toolTip.text: qsTr("Add another account")
backgroundColor: theme.accountsBar.addAccountButtonBackground
onClicked: pageLoader.showPage("AddAccount/AddAccount")
Layout.preferredHeight: theme.baseElementsHeight
HShortcut {
sequences: window.settings.keys.addNewAccount
onActivated: addAccountButton.clicked()
}
}
HButton { HButton {
id: settingsButton id: settingsButton
backgroundColor: theme.accountsBar.settingsButtonBackground backgroundColor: theme.accountsBar.settingsButtonBackground

View File

@ -21,7 +21,7 @@ HTextField {
Keys.onEnterPressed: Keys.onReturnPressed(event) Keys.onEnterPressed: Keys.onReturnPressed(event)
Keys.onReturnPressed: { Keys.onReturnPressed: {
if (window.settings.clearRoomFilterOnEnter) text = "" if (window.settings.clearRoomFilterOnEnter) text = ""
roomList.showRoom() roomList.showRoomAtIndex()
} }
Keys.onEscapePressed: { Keys.onEscapePressed: {
@ -36,13 +36,11 @@ HTextField {
Behavior on opacity { HNumberAnimation {} } Behavior on opacity { HNumberAnimation {} }
HShortcut { HShortcut {
enabled: loader.isCurrent
sequences: window.settings.keys.clearRoomFilter sequences: window.settings.keys.clearRoomFilter
onActivated: filterField.text = "" onActivated: filterField.text = ""
} }
HShortcut { HShortcut {
enabled: loader.isCurrent
sequences: window.settings.keys.toggleFocusMainPane sequences: window.settings.keys.toggleFocusMainPane
onActivated: { onActivated: {
if (filterField.activeFocus) { if (filterField.activeFocus) {

View File

@ -10,7 +10,9 @@ HDrawer {
background: null background: null
// minimumSize: bottomBar.addAccountButton.width // minimumSize: bottomBar.addAccountButton.width
// property alias filter: bottomBar.roomFilter readonly property alias accountBar: accountBar
readonly property alias roomList: roomList
readonly property alias filterRoomsField: filterRoomsField
readonly property bool small: readonly property bool small:
width < theme.controls.avatar.size + theme.spacing * 2 width < theme.controls.avatar.size + theme.spacing * 2
@ -28,17 +30,26 @@ HDrawer {
AccountsBar { AccountsBar {
id: accountBar id: accountBar
accountSwipeView: accountSwipeView roomList: roomList
Layout.fillWidth: false Layout.fillWidth: false
} }
AccountSwipeView { HColumnLayout {
id: accountSwipeView RoomList {
currentIndex: 0 id: roomList
clip: true
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
}
FilterRoomsField {
id: filterRoomsField
roomList: roomList
Layout.fillWidth: true
}
} }
} }
} }

View File

@ -146,7 +146,7 @@ HTileDelegate {
popup: "Popups/InviteToRoomPopup.qml" popup: "Popups/InviteToRoomPopup.qml"
properties: ({ properties: ({
userId: userId, userId: model.for_account,
roomId: model.id, roomId: model.id,
roomName: model.display_name, roomName: model.display_name,
invitingAllowed: Qt.binding(() => model.can_invite) invitingAllowed: Qt.binding(() => model.can_invite)
@ -169,7 +169,7 @@ HTileDelegate {
label.textFormat: Text.StyledText label.textFormat: Text.StyledText
onTriggered: py.callClientCoro( onTriggered: py.callClientCoro(
userId, "join", [model.id] model.for_account, "join", [model.id]
) )
} }
@ -181,7 +181,7 @@ HTileDelegate {
popup: "Popups/LeaveRoomPopup.qml" popup: "Popups/LeaveRoomPopup.qml"
properties: ({ properties: ({
userId: userId, userId: model.for_account,
roomId: model.id, roomId: model.id,
roomName: model.display_name, roomName: model.display_name,
}) })
@ -195,7 +195,7 @@ HTileDelegate {
popup: "Popups/ForgetRoomPopup.qml" popup: "Popups/ForgetRoomPopup.qml"
autoDestruct: false autoDestruct: false
properties: ({ properties: ({
userId: userId, userId: model.for_account,
roomId: model.id, roomId: model.id,
roomName: model.display_name, roomName: model.display_name,
}) })
@ -203,14 +203,12 @@ HTileDelegate {
} }
property string userId
readonly property bool joined: ! invited && ! parted readonly property bool joined: ! invited && ! parted
readonly property bool invited: model.inviter_id && ! parted readonly property bool invited: model.inviter_id && ! parted
readonly property bool parted: model.left readonly property bool parted: model.left
readonly property ListModel eventModel: readonly property ListModel eventModel:
ModelStore.get(userId, model.id, "events") ModelStore.get(model.for_account, model.id, "events")
readonly property QtObject lastEvent: readonly property QtObject lastEvent:
eventModel.count > 0 ? eventModel.get(0) : null eventModel.count > 0 ? eventModel.get(0) : null

View File

@ -7,44 +7,78 @@ import "../Base"
HListView { HListView {
id: roomList id: roomList
model: ModelStore.get(accountModel.id, "rooms") model: ModelStore.get("every_room")
section.property: "for_account"
section.labelPositioning:
ViewSection.InlineLabels | ViewSection.CurrentLabelAtStart
section.delegate: Account {
accountModel: ModelStore.get("accounts").find(section)
width: roomList.width
}
delegate: Room { delegate: Room {
width: roomList.width width: roomList.width
userId: accountModel.id onActivated: showRoomAtIndex(model.index)
onActivated: showRoom(model.index)
} }
onIsCurrentChanged: if (isCurrent) showRoom()
readonly property var sectionIndice: {
const sections = {}
const accounts = ModelStore.get("accounts")
let total = 0
for (let i = 0; i < accounts.count; i++) {
const userId = accounts.get(i).id
sections[userId] = total
total += ModelStore.get(userId, "rooms").count
}
return sections
}
property var accountModel function goToAccount(userId) {
property var roomPane currentIndex = sectionIndice[userId]
property bool isCurrent: false }
function goToAccountNumber(num) {
currentIndex = Object.values(sectionIndice).sort()[num]
}
function showRoom(index=currentIndex) { function showRoomAtIndex(index=currentIndex) {
if (index === -1) index = 0 if (index === -1) index = 0
if (index >= model.count) return index = Math.min(index, model.count - 1)
pageLoader.showRoom(accountModel.id, model.get(index).id)
const room = model.get(index)
pageLoader.showRoom(room.for_account, room.id)
currentIndex = index currentIndex = index
} }
function showAccountRoomAtIndex(index) {
const userId =
model.get(currentIndex === -1 ? 0 : currentIndex).for_account
const rooms = ModelStore.get(userId, "rooms")
if (! rooms.count) return
const room = rooms.get(utils.numberWrapAt(index, rooms.count))
showRoomAtIndex(model.findIndex(room.id))
}
Timer { Timer {
id: showRoomLimiter id: showRoomLimiter
interval: 200 interval: 200
onTriggered: showRoom() onTriggered: showRoomAtIndex()
} }
HShortcut { HShortcut {
enabled: isCurrent
sequences: window.settings.keys.goToPreviousRoom sequences: window.settings.keys.goToPreviousRoom
onActivated: { decrementCurrentIndex(); showRoomLimiter.restart() } onActivated: { decrementCurrentIndex(); showRoomLimiter.restart() }
} }
HShortcut { HShortcut {
enabled: isCurrent
sequences: window.settings.keys.goToNextRoom sequences: window.settings.keys.goToNextRoom
onActivated: { incrementCurrentIndex(); showRoomLimiter.restart() } onActivated: { incrementCurrentIndex(); showRoomLimiter.restart() }
} }
@ -54,28 +88,13 @@ HListView {
Item { Item {
HShortcut { HShortcut {
enabled: isCurrent
sequence: window.settings.keys.focusRoomAtIndex[modelData] sequence: window.settings.keys.focusRoomAtIndex[modelData]
onActivated: showRoom(parseInt(modelData - 1, 10)) onActivated:
showAccountRoomAtIndex(parseInt(modelData - 1, 10))
} }
} }
} }
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.NoButton
onWheel: {
const goingDown = wheel.angleDelta.y < 0
if (! goingDown && roomList.atYBeginning)
roomPane.decrementCurrentIndex()
else if (goingDown && roomList.atYEnd)
roomPane.incrementCurrentIndex()
else
wheel.accepted = false
}
}
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
z: -100 z: -100

View File

@ -14,18 +14,18 @@ QtObject {
ListModel { ListModel {
property var modelId property var modelId
function findIndex(id) { function findIndex(id, default_=null) {
for (let i = 0; i < count; i++) for (let i = 0; i < count; i++)
if (get(i).id === id) return i if (get(i).id === id) return i
return null return default_
} }
function find(id) { function find(id, default_=null) {
for (let i = 0; i < count; i++) for (let i = 0; i < count; i++)
if (get(i).id === id) return get(i) if (get(i).id === id) return get(i)
return null return default_
} }
} }
} }