Gather both Accounts and Rooms in all_rooms model
This commit is contained in:
parent
19243ec5a6
commit
4d3c26abd4
4
TODO.md
4
TODO.md
|
@ -1,13 +1,11 @@
|
||||||
# TODO
|
# TODO
|
||||||
|
|
||||||
- add account number binds
|
- add account number binds
|
||||||
- rename goto*account → scrollto*account
|
|
||||||
|
|
||||||
- fix opacity
|
- remove `import QtQml.Models 2.12`s
|
||||||
- fix left rooms opacity
|
- fix left rooms opacity
|
||||||
- fix escape keybinds (filter rooms, message selection)
|
- fix escape keybinds (filter rooms, message selection)
|
||||||
- fix python getting stuck when loading large room
|
- fix python getting stuck when loading large room
|
||||||
- fix room out of bounds (above section) when filtering and only one match
|
|
||||||
|
|
||||||
- account delegates refactor
|
- account delegates refactor
|
||||||
- lag when switching accounts
|
- lag when switching accounts
|
||||||
|
|
|
@ -31,6 +31,8 @@ class ModelFilter(ModelProxy):
|
||||||
_changed_fields: Optional[Dict[str, Any]] = None,
|
_changed_fields: Optional[Dict[str, Any]] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
if self.accept_source(source):
|
if self.accept_source(source):
|
||||||
|
value = self.convert_item(value)
|
||||||
|
|
||||||
if self.accept_item(value):
|
if self.accept_item(value):
|
||||||
self.__setitem__((source.sync_id, key), value, _changed_fields)
|
self.__setitem__((source.sync_id, key), value, _changed_fields)
|
||||||
self.filtered_out.pop((source.sync_id, key), None)
|
self.filtered_out.pop((source.sync_id, key), None)
|
||||||
|
@ -66,16 +68,25 @@ class ModelFilter(ModelProxy):
|
||||||
callback()
|
callback()
|
||||||
|
|
||||||
|
|
||||||
def refilter(self) -> None:
|
def refilter(
|
||||||
|
self,
|
||||||
|
only_if: Optional[Callable[["ModelItem"], bool]] = None,
|
||||||
|
) -> None:
|
||||||
with self._write_lock:
|
with self._write_lock:
|
||||||
take_out = []
|
take_out = []
|
||||||
bring_back = []
|
bring_back = []
|
||||||
|
|
||||||
for key, item in sorted(self.items(), key=lambda kv: kv[1]):
|
for key, item in sorted(self.items(), key=lambda kv: kv[1]):
|
||||||
|
if only_if and not only_if(item):
|
||||||
|
continue
|
||||||
|
|
||||||
if not self.accept_item(item):
|
if not self.accept_item(item):
|
||||||
take_out.append(key)
|
take_out.append(key)
|
||||||
|
|
||||||
for key, item in self.filtered_out.items():
|
for key, item in self.filtered_out.items():
|
||||||
|
if only_if and not only_if(item):
|
||||||
|
continue
|
||||||
|
|
||||||
if self.accept_item(item):
|
if self.accept_item(item):
|
||||||
bring_back.append(key)
|
bring_back.append(key)
|
||||||
|
|
||||||
|
@ -86,6 +97,7 @@ class ModelFilter(ModelProxy):
|
||||||
for key in bring_back:
|
for key in bring_back:
|
||||||
self[key] = self.filtered_out.pop(key)
|
self[key] = self.filtered_out.pop(key)
|
||||||
|
|
||||||
|
if take_out or bring_back:
|
||||||
for callback in self.items_changed_callbacks:
|
for callback in self.items_changed_callbacks:
|
||||||
callback()
|
callback()
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,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()
|
for_account: str = ""
|
||||||
given_name: str = ""
|
given_name: str = ""
|
||||||
display_name: str = ""
|
display_name: str = ""
|
||||||
main_alias: str = ""
|
main_alias: str = ""
|
||||||
|
@ -118,6 +118,33 @@ class Room(ModelItem):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class AccountOrRoom(Account, Room):
|
||||||
|
type: Union[Type[Account], Type[Room]] = Account
|
||||||
|
|
||||||
|
def __lt__(self, other: "AccountOrRoom") -> bool: # type: ignore
|
||||||
|
return (
|
||||||
|
self.id if self.type is Account else self.for_account,
|
||||||
|
other.type is Account,
|
||||||
|
self.left,
|
||||||
|
other.inviter_id,
|
||||||
|
bool(other.mentions),
|
||||||
|
bool(other.unreads),
|
||||||
|
other.last_event_date,
|
||||||
|
(self.display_name or self.id).lower(),
|
||||||
|
|
||||||
|
) < (
|
||||||
|
other.id if other.type is Account else other.for_account,
|
||||||
|
self.type is Account,
|
||||||
|
other.left,
|
||||||
|
self.inviter_id,
|
||||||
|
bool(self.mentions),
|
||||||
|
bool(self.unreads),
|
||||||
|
self.last_event_date,
|
||||||
|
(other.display_name or other.id).lower(),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Member(ModelItem):
|
class Member(ModelItem):
|
||||||
"""A member in a matrix room."""
|
"""A member in a matrix room."""
|
||||||
|
|
|
@ -25,6 +25,10 @@ class ModelProxy(Model):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def convert_item(self, item: "ModelItem") -> "ModelItem":
|
||||||
|
return item
|
||||||
|
|
||||||
|
|
||||||
def source_item_set(
|
def source_item_set(
|
||||||
self,
|
self,
|
||||||
source: Model,
|
source: Model,
|
||||||
|
@ -33,6 +37,7 @@ class ModelProxy(Model):
|
||||||
_changed_fields: Optional[Dict[str, Any]] = None,
|
_changed_fields: Optional[Dict[str, Any]] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
if self.accept_source(source):
|
if self.accept_source(source):
|
||||||
|
value = self.convert_item(value)
|
||||||
self.__setitem__((source.sync_id, key), value, _changed_fields)
|
self.__setitem__((source.sync_id, key), value, _changed_fields)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
# SPDX-License-Identifier: LGPL-3.0-or-later
|
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
|
||||||
|
from dataclasses import asdict
|
||||||
|
|
||||||
from .filters import FieldSubstringFilter, ModelFilter
|
from .filters import FieldSubstringFilter, ModelFilter
|
||||||
|
from .items import Account, AccountOrRoom
|
||||||
from .model import Model
|
from .model import Model
|
||||||
from .model_item import ModelItem
|
from .model_item import ModelItem
|
||||||
|
|
||||||
|
@ -8,16 +11,38 @@ from .model_item import ModelItem
|
||||||
class AllRooms(FieldSubstringFilter):
|
class AllRooms(FieldSubstringFilter):
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
super().__init__(sync_id="all_rooms", fields=("display_name",))
|
super().__init__(sync_id="all_rooms", fields=("display_name",))
|
||||||
|
self.items_changed_callbacks.append(self.refilter_accounts)
|
||||||
|
|
||||||
|
|
||||||
def accept_source(self, source: Model) -> bool:
|
def accept_source(self, source: Model) -> bool:
|
||||||
return (
|
return source.sync_id == "accounts" or (
|
||||||
isinstance(source.sync_id, tuple) and
|
isinstance(source.sync_id, tuple) and
|
||||||
len(source.sync_id) == 2 and
|
len(source.sync_id) == 2 and
|
||||||
source.sync_id[1] == "rooms" # type: ignore
|
source.sync_id[1] == "rooms" # type: ignore
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def convert_item(self, item: ModelItem) -> AccountOrRoom:
|
||||||
|
return AccountOrRoom(**asdict(item), type=type(item)) # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
def accept_item(self, item: ModelItem) -> bool:
|
||||||
|
matches_filter = super().accept_item(item)
|
||||||
|
|
||||||
|
if item.type is not Account or not self.filter: # type: ignore
|
||||||
|
return matches_filter
|
||||||
|
|
||||||
|
return next(
|
||||||
|
(i for i in self.values() if i.for_account == item.id), False,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def refilter_accounts(self) -> None:
|
||||||
|
self.refilter(
|
||||||
|
lambda i: isinstance(i, AccountOrRoom) and i.type is Account,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class MatchingAccounts(ModelFilter):
|
class MatchingAccounts(ModelFilter):
|
||||||
def __init__(self, all_rooms: AllRooms) -> None:
|
def __init__(self, all_rooms: AllRooms) -> None:
|
||||||
self.all_rooms = all_rooms
|
self.all_rooms = all_rooms
|
||||||
|
@ -35,7 +60,7 @@ class MatchingAccounts(ModelFilter):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return next(
|
return next(
|
||||||
(r for r in self.all_rooms.values() if r.for_account == item.id),
|
(i for i in self.all_rooms.values() if i.id == item.id),
|
||||||
False,
|
False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -16,19 +16,19 @@ HTile {
|
||||||
|
|
||||||
HUserAvatar {
|
HUserAvatar {
|
||||||
id: avatar
|
id: avatar
|
||||||
userId: accountModel.id
|
userId: model.id
|
||||||
displayName: accountModel.display_name
|
displayName: model.display_name
|
||||||
mxc: accountModel.avatar_url
|
mxc: model.avatar_url
|
||||||
radius: 0
|
radius: 0
|
||||||
compact: account.compact
|
compact: account.compact
|
||||||
}
|
}
|
||||||
|
|
||||||
TitleLabel {
|
TitleLabel {
|
||||||
text: accountModel.display_name || accountModel.id
|
text: model.display_name || model.id
|
||||||
color:
|
color:
|
||||||
hovered ?
|
hovered ?
|
||||||
utils.nameColor(
|
utils.nameColor(
|
||||||
accountModel.display_name || accountModel.id.substring(1),
|
model.display_name || model.id.substring(1),
|
||||||
) :
|
) :
|
||||||
theme.accountView.account.name
|
theme.accountView.account.name
|
||||||
|
|
||||||
|
@ -42,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: accountModel.id},
|
"AddChat/AddChat", {userId: model.id},
|
||||||
)
|
)
|
||||||
|
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
@ -57,16 +57,15 @@ HTile {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
contextMenu: AccountContextMenu { userId: accountModel.id }
|
contextMenu: AccountContextMenu { userId: model.id }
|
||||||
|
|
||||||
onLeftClicked: {
|
onLeftClicked: {
|
||||||
pageLoader.showPage(
|
pageLoader.showPage(
|
||||||
"AccountSettings/AccountSettings", { "userId": accountModel.id }
|
"AccountSettings/AccountSettings", { "userId": model.id }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
property var accountModel
|
|
||||||
property bool isCurrent: false
|
property bool isCurrent: false
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,9 @@ HColumnLayout {
|
||||||
roomList.count === 0 || roomList.currentIndex === -1 ?
|
roomList.count === 0 || roomList.currentIndex === -1 ?
|
||||||
-1 :
|
-1 :
|
||||||
model.findIndex(
|
model.findIndex(
|
||||||
roomList.model.get(roomList.currentIndex).for_account, -1,
|
roomList.model.get(roomList.currentIndex).for_account ||
|
||||||
|
roomList.model.get(roomList.currentIndex).id,
|
||||||
|
-1,
|
||||||
)
|
)
|
||||||
|
|
||||||
model: ModelStore.get("matching_accounts")
|
model: ModelStore.get("matching_accounts")
|
||||||
|
@ -77,6 +79,11 @@ HColumnLayout {
|
||||||
|
|
||||||
HLoader {
|
HLoader {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin:
|
||||||
|
accountList.highlightItem ?
|
||||||
|
accountList.highlightItem.border.width :
|
||||||
|
0
|
||||||
|
|
||||||
opacity: model.first_sync_done ? 0 : 1
|
opacity: model.first_sync_done ? 0 : 1
|
||||||
|
|
||||||
active: opacity > 0
|
active: opacity > 0
|
||||||
|
@ -96,14 +103,12 @@ HColumnLayout {
|
||||||
|
|
||||||
contextMenu: AccountContextMenu { userId: model.id }
|
contextMenu: AccountContextMenu { userId: model.id }
|
||||||
|
|
||||||
onLeftClicked: {
|
onLeftClicked: roomList.goToAccount(model.id)
|
||||||
model.id in roomList.sectionIndice ?
|
|
||||||
roomList.goToAccount(model.id) :
|
|
||||||
pageLoader.showPage("AddChat/AddChat", {userId: model.id})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
highlight: Item {
|
highlight: Item {
|
||||||
|
readonly property alias border: border
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: theme.accountsBar.accountList.account.selectedBackground
|
color: theme.accountsBar.accountList.account.selectedBackground
|
||||||
|
@ -112,7 +117,7 @@ HColumnLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
z: 100
|
id: border
|
||||||
width: theme.accountsBar.accountList.account.selectedBorderSize
|
width: theme.accountsBar.accountList.account.selectedBorderSize
|
||||||
height: parent.height
|
height: parent.height
|
||||||
color: theme.accountsBar.accountList.account.selectedBorder
|
color: theme.accountsBar.accountList.account.selectedBorder
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import QtQuick 2.12
|
import QtQuick 2.12
|
||||||
import QtQuick.Layouts 1.12
|
import QtQuick.Layouts 1.12
|
||||||
import QtQml.Models 2.12
|
import QtQml.Models 2.12
|
||||||
|
import Qt.labs.qmlmodels 1.0
|
||||||
import ".."
|
import ".."
|
||||||
import "../Base"
|
import "../Base"
|
||||||
|
|
||||||
|
@ -10,82 +11,96 @@ HListView {
|
||||||
id: roomList
|
id: roomList
|
||||||
model: ModelStore.get("all_rooms")
|
model: ModelStore.get("all_rooms")
|
||||||
|
|
||||||
delegate: Room {
|
delegate: DelegateChooser {
|
||||||
id: room
|
role: "type"
|
||||||
width: roomList.width
|
|
||||||
onActivated: showRoomAtIndex(model.index)
|
DelegateChoice {
|
||||||
|
roleValue: "Account"
|
||||||
|
Account { width: roomList.width }
|
||||||
}
|
}
|
||||||
|
|
||||||
section.property: "for_account"
|
DelegateChoice {
|
||||||
section.labelPositioning:
|
roleValue: "Room"
|
||||||
ViewSection.InlineLabels | ViewSection.CurrentLabelAtStart
|
Room {
|
||||||
|
|
||||||
section.delegate: Account {
|
|
||||||
width: roomList.width
|
width: roomList.width
|
||||||
accountModel: ModelStore.get("accounts").find(section)
|
onActivated: showItemAtIndex(model.index)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onFilterChanged: py.callCoro("set_substring_filter", ["all_rooms", filter])
|
onFilterChanged: py.callCoro("set_substring_filter", ["all_rooms", filter])
|
||||||
|
|
||||||
|
|
||||||
property string filter: ""
|
property string filter: ""
|
||||||
readonly property var sectionIndice: {
|
readonly property var accountIndice: {
|
||||||
const sections = {}
|
const accounts = {}
|
||||||
let currentUserId = null
|
|
||||||
|
|
||||||
for (let i = 0; i < model.count; i++) {
|
for (let i = 0; i < model.count; i++) {
|
||||||
const userId = model.get(i).for_account
|
if (model.get(i).type === "Account")
|
||||||
|
accounts[model.get(i).id] = i
|
||||||
if (userId !== currentUserId) {
|
|
||||||
sections[userId] = i
|
|
||||||
currentUserId = userId
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return sections
|
return accounts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function goToAccount(userId) {
|
function goToAccount(userId) {
|
||||||
currentIndex = sectionIndice[userId]
|
model.get(accountIndice[userId] + 1).type === "Room" ?
|
||||||
|
currentIndex = accountIndice[userId] + 1 :
|
||||||
|
currentIndex = accountIndice[userId]
|
||||||
|
|
||||||
|
showItemLimiter.restart()
|
||||||
}
|
}
|
||||||
|
|
||||||
function goToAccountNumber(num) {
|
function goToAccountNumber(num) {
|
||||||
currentIndex = Object.values(sectionIndice).sort()[num]
|
const index = Object.values(accountIndice).sort()[num]
|
||||||
|
|
||||||
|
model.get(index + 1).type === "Room" ?
|
||||||
|
currentIndex = index + 1 :
|
||||||
|
currentIndex = index
|
||||||
|
|
||||||
|
showItemLimiter.restart()
|
||||||
}
|
}
|
||||||
|
|
||||||
function showRoomAtIndex(index=currentIndex) {
|
function showItemAtIndex(index=currentIndex) {
|
||||||
if (index === -1) index = 0
|
if (index === -1) index = 0
|
||||||
index = Math.min(index, model.count - 1)
|
index = Math.min(index, model.count - 1)
|
||||||
|
|
||||||
const room = model.get(index)
|
const item = model.get(index)
|
||||||
pageLoader.showRoom(room.for_account, room.id)
|
|
||||||
|
item.type === "Account" ?
|
||||||
|
pageLoader.showPage(
|
||||||
|
"AccountSettings/AccountSettings", { "userId": item.id }
|
||||||
|
) :
|
||||||
|
pageLoader.showRoom(item.for_account, item.id)
|
||||||
|
|
||||||
currentIndex = index
|
currentIndex = index
|
||||||
}
|
}
|
||||||
|
|
||||||
function showAccountRoomAtIndex(index) {
|
function showAccountRoomAtIndex(index) {
|
||||||
const currentUserId = model.get(
|
const item = model.get(currentIndex === -1 ? 0 : currentIndex)
|
||||||
currentIndex === -1 ? 0 : currentIndex
|
|
||||||
).for_account
|
|
||||||
|
|
||||||
showRoomAtIndex(sectionIndice[currentUserId] + index)
|
const currentUserId =
|
||||||
|
item.type === "Account" ? item.id : item.for_account
|
||||||
|
|
||||||
|
showItemAtIndex(accountIndice[currentUserId] + 1 + index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: showRoomLimiter
|
id: showItemLimiter
|
||||||
interval: 200
|
interval: 200
|
||||||
onTriggered: showRoomAtIndex()
|
onTriggered: showItemAtIndex()
|
||||||
}
|
}
|
||||||
|
|
||||||
HShortcut {
|
HShortcut {
|
||||||
sequences: window.settings.keys.goToPreviousRoom
|
sequences: window.settings.keys.goToPreviousRoom
|
||||||
onActivated: { decrementCurrentIndex(); showRoomLimiter.restart() }
|
onActivated: { decrementCurrentIndex(); showItemLimiter.restart() }
|
||||||
}
|
}
|
||||||
|
|
||||||
HShortcut {
|
HShortcut {
|
||||||
sequences: window.settings.keys.goToNextRoom
|
sequences: window.settings.keys.goToNextRoom
|
||||||
onActivated: { incrementCurrentIndex(); showRoomLimiter.restart() }
|
onActivated: { incrementCurrentIndex(); showItemLimiter.restart() }
|
||||||
}
|
}
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user