* Add Keys.Rooms.Direct configuration Keybinding to jump to specific room id in specific account id, or the first occurence of specific room id in any account. * Default binding was a bad idea This example binding was preventing the user from binding Ctrl+G,Ctrl+M to something else. * Use const instead of var * Use showItemAtIndex for direct room switching This is a simpler implementation that better fits in the existing codebase and doesn't really have drawbacks. * Use existing findIndex From roomList.model. Instead of reinventing it * Made example not a real room Earlier I made it point to the Mirage room * Add instructions for copying room ID After noticing that these IDs do not match Matrix room addresses, I felt it was necessary to explain this here, even if it's already explained in other parts of the configuration file. * Use .split(" ") for splitting descriptions This is a more readable implementation. * Fix shortcuts breaking on config reload Wrapping HShortcut in Loader makes it destructible. See d53978f62bab35cdc7e115c50f0571f736814582 * Cleanup showRoomByDescription method, now showById - "Room description" is a vague, it sounds like this is about the room topic too. Instead of having a function that takes a string with a certain format, take explicit arguments for the user and room ID, this way we don't need comments to explain what's going on either - Reduce indentations and {} noise to make it simpler to read * More details for direct room binds config comment Co-authored-by: miruka <miruka@disroot.org>
324 lines
9.4 KiB
QML
324 lines
9.4 KiB
QML
// Copyright Mirage authors & contributors <https://github.com/mirukana/mirage>
|
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
|
|
import QtQuick 2.12
|
|
import QtQuick.Layouts 1.12
|
|
import Qt.labs.qmlmodels 1.0
|
|
import ".."
|
|
import "../Base"
|
|
|
|
HListView {
|
|
id: roomList
|
|
|
|
property string filter: ""
|
|
|
|
property bool keepListCentered: true
|
|
|
|
readonly property bool currentShouldBeAccount:
|
|
window.uiState.page === "Pages/AccountSettings/AccountSettings.qml" ||
|
|
window.uiState.page === "Pages/AddChat/AddChat.qml"
|
|
|
|
readonly property bool currentShouldBeRoom:
|
|
window.uiState.page === "Pages/Chat/Chat.qml"
|
|
|
|
readonly property string wantedUserId: (
|
|
window.uiState.pageProperties.userRoomId ||
|
|
[window.uiState.pageProperties.userId, ""]
|
|
)[0] || ""
|
|
|
|
readonly property string wantedRoomId: (
|
|
window.uiState.pageProperties.userRoomId ||
|
|
["", window.uiState.pageProperties.roomId]
|
|
)[1] || ""
|
|
|
|
readonly property var accountIndice: {
|
|
const accounts = {}
|
|
|
|
for (let i = 0; i < model.count; i++) {
|
|
if (model.get(i).type === "Account")
|
|
accounts[model.get(i).id] = i
|
|
}
|
|
|
|
return accounts
|
|
}
|
|
|
|
function goToAccount(userId) {
|
|
currentIndex = accountIndice[userId]
|
|
showItemLimiter.restart()
|
|
}
|
|
|
|
function goToAccountNumber(num) {
|
|
currentIndex = Object.entries(accountIndice)[num][1]
|
|
showItemLimiter.restart()
|
|
}
|
|
|
|
function showItemAtIndex(index=currentIndex, fromClick=false) {
|
|
if (index === -1) index = 0
|
|
index = Math.min(index, model.count - 1)
|
|
|
|
const item = model.get(index)
|
|
|
|
item.type === "Account" ?
|
|
pageLoader.show(
|
|
"Pages/AccountSettings/AccountSettings.qml", { "userId": item.id },
|
|
) :
|
|
pageLoader.showRoom(item.for_account, item.id)
|
|
|
|
if (fromClick && ! window.settings.RoomList.click_centers)
|
|
keepListCentered = false
|
|
|
|
currentIndex = index
|
|
|
|
if (fromClick && ! window.settings.RoomList.click_centers)
|
|
keepListCentered = true
|
|
}
|
|
|
|
function showById(roomId, accountId=null) {
|
|
// If only a room ID is passed, first account with this room is used
|
|
if (accountId === null) {
|
|
const roomIndex = model.findIndex(roomId)
|
|
|
|
roomIndex === null ?
|
|
console.warn("No account with such room ID:", roomId) :
|
|
showItemAtIndex(roomIndex)
|
|
|
|
return
|
|
}
|
|
|
|
if (! (accountId in accountIndice)) {
|
|
console.warn("No such account:", accountId)
|
|
return
|
|
}
|
|
|
|
pageLoader.showRoom(accountId, roomId)
|
|
startCorrectItemSearch()
|
|
}
|
|
|
|
function showAccountRoomAtIndex(index) {
|
|
const item = model.get(currentIndex === -1 ? 0 : currentIndex)
|
|
|
|
const currentUserId =
|
|
item.type === "Account" ? item.id : item.for_account
|
|
|
|
showItemAtIndex(accountIndice[currentUserId] + 1 + index)
|
|
}
|
|
|
|
function cycleUnreadRooms(forward=true, highlights=false) {
|
|
const prop = highlights ? "highlights" : "unreads"
|
|
const local_prop = highlights ? "highlights" : "local_unreads"
|
|
const start = currentIndex === -1 ? 0 : currentIndex
|
|
let index = start
|
|
|
|
while (true) {
|
|
index += forward ? 1 : -1
|
|
|
|
if (index < 0) index = model.count - 1
|
|
if (index > model.count - 1) index = 0
|
|
|
|
if (index === start && highlights)
|
|
return cycleUnreadRooms(forward, false)
|
|
else if (index === start)
|
|
return false
|
|
|
|
const item = model.get(index)
|
|
|
|
if (item.type === "Room" && (item[prop] || item[local_prop])) {
|
|
currentIndex = index
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
|
|
function startCorrectItemSearch() {
|
|
correctTimer.start()
|
|
}
|
|
|
|
function setCorrectCurrentItem() {
|
|
if (! currentShouldBeRoom && ! currentShouldBeAccount) {
|
|
currentIndex = -1
|
|
return null
|
|
}
|
|
|
|
for (let i = 0; i < model.count; i++) {
|
|
const item = model.get(i)
|
|
|
|
if ((
|
|
currentShouldBeRoom &&
|
|
item.type === "Room" &&
|
|
item.id === wantedRoomId &&
|
|
item.for_account === wantedUserId
|
|
) || (
|
|
currentShouldBeAccount &&
|
|
item.type === "Account" &&
|
|
item.id === wantedUserId
|
|
)) {
|
|
currentIndex = i
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
highlightRangeMode:
|
|
keepListCentered ? ListView.ApplyRange : ListView.NoHighlightRange
|
|
|
|
model: ModelStore.get("all_rooms")
|
|
|
|
delegate: DelegateChooser {
|
|
role: "type"
|
|
|
|
DelegateChoice {
|
|
roleValue: "Account"
|
|
AccountDelegate {
|
|
width: roomList.width
|
|
leftPadding: theme.spacing
|
|
rightPadding: 0 // the right buttons have padding
|
|
|
|
filterActive: Boolean(filter)
|
|
enableKeybinds: Boolean(
|
|
roomList.model.get(currentIndex) && (
|
|
roomList.model.get(currentIndex).for_account ||
|
|
roomList.model.get(currentIndex).id
|
|
) === model.id
|
|
)
|
|
|
|
totalMessageIndicator.visible: false
|
|
|
|
onLeftClicked: showItemAtIndex(model.index, true)
|
|
onCollapsedChanged:
|
|
if (wantedUserId === model.id) startCorrectItemSearch()
|
|
|
|
onWentToAccountPage: roomList.currentIndex = model.index
|
|
}
|
|
}
|
|
|
|
DelegateChoice {
|
|
roleValue: "Room"
|
|
RoomDelegate {
|
|
width: roomList.width
|
|
onLeftClicked: showItemAtIndex(model.index, true)
|
|
}
|
|
}
|
|
}
|
|
|
|
onFilterChanged: {
|
|
py.callCoro("set_string_filter", ["all_rooms", filter], () => {
|
|
if (filter) {
|
|
currentIndex = 1 // highlight the first matching room
|
|
return
|
|
}
|
|
|
|
const item = model.get(currentIndex)
|
|
|
|
if (
|
|
! filter &&
|
|
item && (
|
|
currentIndex === 1 || // required, related to the if above
|
|
(
|
|
currentShouldBeAccount &&
|
|
wantedUserId !== item.id
|
|
) || (
|
|
currentShouldBeRoom && (
|
|
wantedUserId !== item.for_account ||
|
|
wantedRoomId !== item.id
|
|
)
|
|
)
|
|
)
|
|
)
|
|
startCorrectItemSearch()
|
|
})
|
|
}
|
|
|
|
Connections {
|
|
target: pageLoader
|
|
onPreviousShown: (componentUrl, properties) => {
|
|
if (setCorrectCurrentItem() === false) startCorrectItemSearch()
|
|
}
|
|
}
|
|
|
|
Timer {
|
|
// On startup, the account/room takes an unknown amount of time to
|
|
// arrive in the model, try to find it until then.
|
|
id: correctTimer
|
|
interval: 200
|
|
running: currentIndex === -1
|
|
repeat: true
|
|
triggeredOnStart: true
|
|
onTriggered: setCorrectCurrentItem()
|
|
onRunningChanged: if (running && currentIndex !== -1) currentIndex = -1
|
|
}
|
|
|
|
Timer {
|
|
id: showItemLimiter
|
|
interval: 100
|
|
onTriggered: showItemAtIndex()
|
|
}
|
|
|
|
HShortcut {
|
|
sequences: window.settings.Keys.Rooms.previous
|
|
onActivated: { decrementCurrentIndex(); showItemLimiter.restart() }
|
|
}
|
|
|
|
HShortcut {
|
|
sequences: window.settings.Keys.Rooms.next
|
|
onActivated: { incrementCurrentIndex(); showItemLimiter.restart() }
|
|
}
|
|
|
|
HShortcut {
|
|
sequences: window.settings.Keys.Rooms.previous_unread
|
|
onActivated: { cycleUnreadRooms(false) && showItemLimiter.restart() }
|
|
}
|
|
|
|
HShortcut {
|
|
sequences: window.settings.Keys.Rooms.next_unread
|
|
onActivated: { cycleUnreadRooms(true) && showItemLimiter.restart() }
|
|
}
|
|
|
|
HShortcut {
|
|
sequences: window.settings.Keys.Rooms.previous_highlight
|
|
onActivated: cycleUnreadRooms(false, true) && showItemLimiter.restart()
|
|
}
|
|
|
|
HShortcut {
|
|
sequences: window.settings.Keys.Rooms.next_highlight
|
|
onActivated: cycleUnreadRooms(true, true) && showItemLimiter.restart()
|
|
}
|
|
|
|
Instantiator {
|
|
model: Object.keys(window.settings.Keys.Accounts.AtIndex)
|
|
delegate: Loader {
|
|
sourceComponent: HShortcut {
|
|
sequences: window.settings.Keys.Accounts.AtIndex[modelData]
|
|
onActivated: goToAccountNumber(parseInt(modelData, 10) - 1)
|
|
}
|
|
}
|
|
}
|
|
|
|
Instantiator {
|
|
model: Object.keys(window.settings.Keys.Rooms.AtIndex)
|
|
delegate: Loader {
|
|
sourceComponent: HShortcut {
|
|
sequences: window.settings.Keys.Rooms.AtIndex[modelData]
|
|
onActivated: showAccountRoomAtIndex(parseInt(modelData, 10) - 1)
|
|
}
|
|
}
|
|
}
|
|
|
|
Instantiator {
|
|
model: Object.keys(window.settings.Keys.Rooms.Direct)
|
|
delegate: Loader {
|
|
sourceComponent: HShortcut {
|
|
sequences: window.settings.Keys.Rooms.Direct[modelData]
|
|
onActivated: showById(...modelData.split(/\s+/).reverse())
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
anchors.fill: parent
|
|
z: -100
|
|
color: theme.mainPane.listView.background
|
|
}
|
|
}
|