Make offline presence to stop sync
Setting the presence of an account to offline will make the client to end sync task and will prevent messages from being sent. Setting it to online again or any other presence will start sync task again. Left: - Local echo to presence change - UI Control to affect all members presence - Block more requests to be sent (e.g. member actions)
This commit is contained in:
parent
3fa35b88c9
commit
a3c9ac20c6
|
@ -132,7 +132,7 @@ class Backend:
|
|||
)
|
||||
|
||||
try:
|
||||
await client.login(password)
|
||||
await client.login(password, order=order)
|
||||
except MatrixError:
|
||||
await client.close()
|
||||
raise
|
||||
|
@ -142,22 +142,7 @@ class Backend:
|
|||
await client.logout()
|
||||
return client.user_id
|
||||
|
||||
if order is None and not self.models["accounts"]:
|
||||
order = 0
|
||||
elif order is None:
|
||||
order = max(
|
||||
account.order
|
||||
for i, account in enumerate(self.models["accounts"].values())
|
||||
) + 1
|
||||
|
||||
account = Account(client.user_id, order)
|
||||
|
||||
self.clients[client.user_id] = client
|
||||
self.models["accounts"][client.user_id] = account
|
||||
|
||||
# Get or create presence for account
|
||||
presence = self.presences.setdefault(client.user_id, Presence())
|
||||
presence.members["account", client.user_id] = account
|
||||
self.clients[client.user_id] = client
|
||||
|
||||
return client.user_id
|
||||
|
||||
|
@ -168,7 +153,6 @@ class Backend:
|
|||
token: str,
|
||||
device_id: str,
|
||||
homeserver: str = "https://matrix.org",
|
||||
order: int = -1,
|
||||
state: str = "online",
|
||||
) -> None:
|
||||
"""Create and register a `MatrixClient` with known account details."""
|
||||
|
@ -178,14 +162,7 @@ class Backend:
|
|||
user=user_id, homeserver=homeserver, device_id=device_id,
|
||||
)
|
||||
|
||||
account = Account(user_id, order)
|
||||
|
||||
self.clients[user_id] = client
|
||||
self.models["accounts"][user_id] = account
|
||||
|
||||
# Get or create presence for account
|
||||
presence = self.presences.setdefault(user_id, Presence())
|
||||
presence.members["account", user_id] = account
|
||||
self.clients[user_id] = client
|
||||
|
||||
await client.resume(user_id, token, device_id, state)
|
||||
|
||||
|
@ -194,14 +171,19 @@ class Backend:
|
|||
"""Call `resume_client` for all saved accounts in user config."""
|
||||
|
||||
async def resume(user_id: str, info: Dict[str, Any]) -> str:
|
||||
# Get or create account model
|
||||
self.models["accounts"].setdefault(
|
||||
user_id, Account(user_id, info.get("order", -1)),
|
||||
)
|
||||
|
||||
await self.resume_client(
|
||||
user_id = user_id,
|
||||
token = info["token"],
|
||||
device_id = info["device_id"],
|
||||
homeserver = info["homeserver"],
|
||||
order = info.get("order", -1),
|
||||
state = info.get("presence", "online"),
|
||||
)
|
||||
|
||||
return user_id
|
||||
|
||||
return await asyncio.gather(*(
|
||||
|
|
|
@ -40,7 +40,7 @@ from .errors import (
|
|||
from .html_markdown import HTML_PROCESSOR as HTML
|
||||
from .media_cache import Media, Thumbnail
|
||||
from .models.items import (
|
||||
Event, Member, Presence, Room, Upload, UploadStatus, ZeroDate,
|
||||
Account, Event, Member, Presence, Room, Upload, UploadStatus, ZeroDate,
|
||||
)
|
||||
from .models.model_store import ModelStore
|
||||
from .nio_callbacks import NioCallbacks
|
||||
|
@ -231,14 +231,36 @@ class MatrixClient(nio.AsyncClient):
|
|||
return f"{__display_name__} on {os_name} {os_ver}".rstrip()
|
||||
|
||||
|
||||
async def login(self, password: str, device_name: str = "") -> None:
|
||||
async def login(
|
||||
self, password: str,
|
||||
device_name: str = "",
|
||||
order: Optional[int] = None,
|
||||
) -> None:
|
||||
"""Login to the server using the account's password."""
|
||||
|
||||
await super().login(
|
||||
password, device_name or self.default_device_name(),
|
||||
)
|
||||
|
||||
self.start_task = asyncio.ensure_future(self._start())
|
||||
if order is None and not self.models["accounts"]:
|
||||
order = 0
|
||||
elif order is None:
|
||||
order = max(
|
||||
account.order
|
||||
for i, account in enumerate(self.models["accounts"].values())
|
||||
) + 1
|
||||
|
||||
# Get or create account model
|
||||
# We need to create account model in here, because _start() needs it
|
||||
account = self.models["accounts"].setdefault(
|
||||
self.user_id, Account(self.user_id, order),
|
||||
)
|
||||
|
||||
# TODO: set presence on login
|
||||
self._presence = "online"
|
||||
account.presence = Presence.State.online
|
||||
account.connecting = True
|
||||
self.start_task = asyncio.ensure_future(self._start())
|
||||
|
||||
|
||||
async def resume(
|
||||
|
@ -251,32 +273,21 @@ class MatrixClient(nio.AsyncClient):
|
|||
"""Login to the server using an existing access token."""
|
||||
|
||||
response = nio.LoginResponse(user_id, device_id, token)
|
||||
account = self.models["accounts"][user_id]
|
||||
await self.receive_response(response)
|
||||
|
||||
self._presence = "offline" if state == "invisible" else state
|
||||
self.start_task = asyncio.ensure_future(self._start())
|
||||
account.presence = Presence.State(state)
|
||||
|
||||
if state == "invisible":
|
||||
self.models["accounts"][self.user_id].presence = \
|
||||
Presence.State.invisible
|
||||
if state != "offline":
|
||||
account.connecting = True
|
||||
self.start_task = asyncio.ensure_future(self._start())
|
||||
|
||||
|
||||
async def logout(self) -> None:
|
||||
"""Logout from the server. This will delete the device."""
|
||||
|
||||
tasks = (
|
||||
self.profile_task,
|
||||
self.sync_task,
|
||||
self.server_config_task,
|
||||
self.start_task,
|
||||
)
|
||||
|
||||
for task in tasks:
|
||||
if task:
|
||||
task.cancel()
|
||||
with suppress(asyncio.CancelledError):
|
||||
await task
|
||||
|
||||
await self._stop()
|
||||
await super().logout()
|
||||
await self.close()
|
||||
|
||||
|
@ -300,8 +311,6 @@ class MatrixClient(nio.AsyncClient):
|
|||
if future.cancelled(): # Account logged out
|
||||
return
|
||||
|
||||
account = self.models["accounts"][self.user_id]
|
||||
|
||||
try:
|
||||
account.max_upload_size = future.result()
|
||||
except Exception:
|
||||
|
@ -316,6 +325,13 @@ class MatrixClient(nio.AsyncClient):
|
|||
on_server_config_response,
|
||||
)
|
||||
|
||||
account = self.models["accounts"][self.user_id]
|
||||
|
||||
# Get or create presence for account
|
||||
presence = self.backend.presences.setdefault(self.user_id, Presence())
|
||||
presence.account = account
|
||||
presence.presence = Presence.State(self._presence)
|
||||
|
||||
self.profile_task = asyncio.ensure_future(self.update_own_profile())
|
||||
|
||||
self.server_config_task = asyncio.ensure_future(
|
||||
|
@ -362,6 +378,31 @@ class MatrixClient(nio.AsyncClient):
|
|||
await asyncio.sleep(5)
|
||||
|
||||
|
||||
async def _stop(self) -> None:
|
||||
"""Stop client tasks. Will prevent client to receive further events."""
|
||||
|
||||
tasks = (
|
||||
self.profile_task,
|
||||
self.sync_task,
|
||||
self.server_config_task,
|
||||
self.start_task,
|
||||
)
|
||||
|
||||
for task in tasks:
|
||||
if task:
|
||||
task.cancel()
|
||||
with suppress(asyncio.CancelledError):
|
||||
await task
|
||||
|
||||
self.first_sync_done.clear()
|
||||
|
||||
# Remove account model from presence update
|
||||
presence = self.backend.presences.get(self.user_id, None)
|
||||
|
||||
if presence:
|
||||
presence.members.pop(("account", self.user_id), None)
|
||||
|
||||
|
||||
async def update_own_profile(self) -> None:
|
||||
"""Fetch our profile from server and Update our model `Account`."""
|
||||
|
||||
|
@ -478,6 +519,12 @@ class MatrixClient(nio.AsyncClient):
|
|||
mentions = mentions,
|
||||
)
|
||||
|
||||
while (
|
||||
self.models["accounts"][self.user_id].presence ==
|
||||
Presence.State.offline
|
||||
):
|
||||
await asyncio.sleep(0.2)
|
||||
|
||||
await self._send_message(room_id, content, tx_id)
|
||||
|
||||
|
||||
|
@ -503,6 +550,12 @@ class MatrixClient(nio.AsyncClient):
|
|||
async def send_file(self, room_id: str, path: Union[Path, str]) -> None:
|
||||
"""Send a `m.file`, `m.image`, `m.audio` or `m.video` message."""
|
||||
|
||||
while (
|
||||
self.models["accounts"][self.user_id].presence ==
|
||||
Presence.State.offline
|
||||
):
|
||||
await asyncio.sleep(0.2)
|
||||
|
||||
item_uuid = uuid4()
|
||||
|
||||
try:
|
||||
|
@ -1070,8 +1123,10 @@ class MatrixClient(nio.AsyncClient):
|
|||
"""Set typing notice to the server."""
|
||||
|
||||
# Do not send typing notice if the user is invisible
|
||||
if self.models["accounts"][self.user_id].presence != \
|
||||
Presence.State.invisible:
|
||||
if (
|
||||
self.models["accounts"][self.user_id].presence not in
|
||||
[Presence.State.invisible, Presence.State.offline]
|
||||
):
|
||||
await super().room_typing(room_id, typing_state, timeout)
|
||||
|
||||
|
||||
|
@ -1237,21 +1292,46 @@ class MatrixClient(nio.AsyncClient):
|
|||
) -> None:
|
||||
"""Set presence state for this account."""
|
||||
|
||||
account = self.models["accounts"][self.user_id]
|
||||
status_msg = status_msg if status_msg is not None else (
|
||||
self.models["accounts"][self.user_id].status_msg
|
||||
)
|
||||
|
||||
if presence == "offline":
|
||||
# Do not do anything if account is offline and setting to offline
|
||||
if account.presence == Presence.State.offline:
|
||||
return
|
||||
|
||||
await self._stop()
|
||||
|
||||
# Uppdate manually since we may not receive the presence event back
|
||||
# in time
|
||||
account.presence = Presence.State.offline
|
||||
account.currently_active = False
|
||||
elif (
|
||||
presence != "offline" and
|
||||
account.presence == Presence.State.offline
|
||||
):
|
||||
account.connecting = True
|
||||
self.start_task = asyncio.ensure_future(self._start())
|
||||
|
||||
# Assign invisible on model in here, because server will tell us we are
|
||||
# offline
|
||||
if presence == "invisible":
|
||||
account.presence = Presence.State.invisible
|
||||
|
||||
if not account.presence_support:
|
||||
account.presence = Presence.State(presence)
|
||||
|
||||
await self.backend.saved_accounts.update(
|
||||
self.user_id, presence=presence,
|
||||
)
|
||||
|
||||
await super().set_presence(
|
||||
"offline" if presence == "invisible" else presence,
|
||||
status_msg,
|
||||
)
|
||||
|
||||
# Assign invisible on model in here, because server will tell us we are
|
||||
# offline
|
||||
if presence == "invisible":
|
||||
self.models["accounts"][self.user_id].presence = \
|
||||
Presence.State.invisible
|
||||
|
||||
|
||||
async def import_keys(self, infile: str, passphrase: str) -> None:
|
||||
"""Import decryption keys from a file, then retry decrypting events."""
|
||||
|
|
|
@ -56,27 +56,33 @@ class Presence():
|
|||
last_active_ago: int = -1
|
||||
status_msg: str = ""
|
||||
|
||||
members: Dict[Tuple[str, str], Union["Member", "Account"]] = \
|
||||
field(default_factory=dict)
|
||||
members: Dict[Tuple[str, str], "Member"] = field(default_factory=dict)
|
||||
account: Optional["Account"] = None
|
||||
|
||||
def update_members(self):
|
||||
def update_members(self) -> None:
|
||||
for member in self.members.values():
|
||||
# Do not update if member is changing to invisible
|
||||
# Because when setting invisible presence will give us presence
|
||||
# event telling us we are offline, we do not want to set member
|
||||
# presence to offline.
|
||||
if (
|
||||
member.presence == self.State.invisible
|
||||
) and (
|
||||
self.presence == self.State.offline
|
||||
):
|
||||
continue
|
||||
|
||||
member.presence = self.presence
|
||||
member.status_msg = self.status_msg
|
||||
member.last_active_ago = self.last_active_ago
|
||||
member.currently_active = self.currently_active
|
||||
|
||||
def update_account(self) -> None:
|
||||
# Do not update if account is changing to invisible.
|
||||
# When setting presence to invisible, the server will give us a
|
||||
# presence event telling us we are offline, but we do not want to set
|
||||
# account presence to offline.
|
||||
if (
|
||||
not self.account or
|
||||
self.account.presence == self.State.invisible and
|
||||
self.presence == self.State.offline
|
||||
):
|
||||
return
|
||||
|
||||
self.account.presence = self.presence
|
||||
self.account.status_msg = self.status_msg
|
||||
self.account.last_active_ago = self.last_active_ago
|
||||
self.account.currently_active = self.currently_active
|
||||
|
||||
|
||||
@dataclass
|
||||
class Account(ModelItem):
|
||||
|
@ -88,7 +94,7 @@ class Account(ModelItem):
|
|||
avatar_url: str = ""
|
||||
max_upload_size: int = 0
|
||||
profile_updated: datetime = ZeroDate
|
||||
first_sync_done: bool = False
|
||||
connecting: bool = False
|
||||
total_unread: int = 0
|
||||
total_highlights: int = 0
|
||||
local_unreads: bool = False
|
||||
|
@ -96,11 +102,11 @@ class Account(ModelItem):
|
|||
|
||||
# For some reason, Account cannot inherit Presence, because QML keeps
|
||||
# complaining type error on unknown file
|
||||
presence_support: bool = False
|
||||
presence: Presence.State = Presence.State.offline
|
||||
currently_active: bool = False
|
||||
last_active_ago: int = -1
|
||||
status_msg: str = ""
|
||||
presence_support: bool = False
|
||||
presence: Presence.State = Presence.State.offline
|
||||
currently_active: bool = False
|
||||
last_active_ago: int = -1
|
||||
status_msg: str = ""
|
||||
|
||||
def __lt__(self, other: "Account") -> bool:
|
||||
"""Sort by order, then by user ID."""
|
||||
|
@ -220,7 +226,7 @@ class AccountOrRoom(Account, Room):
|
|||
|
||||
|
||||
@dataclass
|
||||
class Member(Presence, ModelItem):
|
||||
class Member(ModelItem):
|
||||
"""A member in a matrix room."""
|
||||
|
||||
id: str = field()
|
||||
|
@ -234,6 +240,11 @@ class Member(Presence, ModelItem):
|
|||
last_read_event: str = ""
|
||||
last_read_at: datetime = ZeroDate
|
||||
|
||||
presence: Presence.State = Presence.State.offline
|
||||
currently_active: bool = False
|
||||
last_active_ago: int = -1
|
||||
status_msg: str = ""
|
||||
|
||||
def __lt__(self, other: "Member") -> bool:
|
||||
"""Sort by presence, power level, then by display name/user ID."""
|
||||
|
||||
|
|
|
@ -106,7 +106,7 @@ class NioCallbacks:
|
|||
self.client.first_sync_date = datetime.now()
|
||||
|
||||
account = self.models["accounts"][self.user_id]
|
||||
account.first_sync_done = True
|
||||
account.connecting = False
|
||||
|
||||
|
||||
async def onKeysQueryResponse(self, resp: nio.KeysQueryResponse) -> None:
|
||||
|
@ -612,11 +612,21 @@ class NioCallbacks:
|
|||
presence.update_members()
|
||||
|
||||
# Check if presence event is ours
|
||||
if ev.user_id in self.models["accounts"]:
|
||||
if (
|
||||
ev.user_id in self.models["accounts"] and
|
||||
presence.presence != Presence.State.offline
|
||||
):
|
||||
account = self.models["accounts"][ev.user_id]
|
||||
|
||||
# Servers that send presence events support presence
|
||||
self.models["accounts"][ev.user_id].presence_support = True
|
||||
account.presence_support = True
|
||||
|
||||
# Save the presence for the next resume
|
||||
await self.client.backend.saved_accounts.add(ev.user_id)
|
||||
await self.client.backend.saved_accounts.update(
|
||||
user_id = ev.user_id,
|
||||
presence = presence.presence.value,
|
||||
)
|
||||
|
||||
presence.update_account()
|
||||
|
||||
self.client.backend.presences[ev.user_id] = presence
|
||||
|
|
|
@ -184,7 +184,7 @@ class Accounts(JSONDataFile):
|
|||
|
||||
client = self.backend.clients[user_id]
|
||||
saved = await self.read()
|
||||
presence = self.backend.models["accounts"][user_id].presence.value
|
||||
account = self.backend.models["accounts"][user_id]
|
||||
|
||||
await self.write({
|
||||
**saved,
|
||||
|
@ -193,8 +193,10 @@ class Accounts(JSONDataFile):
|
|||
"token": client.access_token,
|
||||
"device_id": client.device_id,
|
||||
"enabled": True,
|
||||
"presence": presence or "online",
|
||||
"order": max([
|
||||
"presence": account.presence.value,
|
||||
|
||||
# Can account.order converge with any other saved value?
|
||||
"order": account.order if account.order >= 0 else max([
|
||||
account.get("order", i)
|
||||
for i, account in enumerate(saved.values())
|
||||
] or [-1]) + 1,
|
||||
|
@ -202,6 +204,24 @@ class Accounts(JSONDataFile):
|
|||
})
|
||||
|
||||
|
||||
async def update(
|
||||
self,
|
||||
user_id: str,
|
||||
enabled: Optional[str] = None,
|
||||
presence: Optional[str] = None,
|
||||
order: Optional[int] = None,
|
||||
) -> None:
|
||||
"""Update existing account in the config and write to disk."""
|
||||
|
||||
saved = await self.read()
|
||||
|
||||
saved[user_id]["enabled"] = enabled or saved[user_id]["enabled"]
|
||||
saved[user_id]["presence"] = presence or saved[user_id]["presence"]
|
||||
saved[user_id]["order"] = order or saved[user_id]["order"]
|
||||
|
||||
await self.write({**saved})
|
||||
|
||||
|
||||
async def delete(self, user_id: str) -> None:
|
||||
"""Delete an account from the config and write it on disk."""
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Shapes 1.15
|
||||
import QtQuick.Shapes 1.12
|
||||
|
||||
HAvatar {
|
||||
name: displayName || userId.substring(1) // no leading @
|
||||
|
|
|
@ -12,18 +12,16 @@ HMenu {
|
|||
property string userId
|
||||
property string presence
|
||||
property string statusMsg
|
||||
property bool firstSyncDone
|
||||
|
||||
onOpened: statusText.forceActiveFocus()
|
||||
|
||||
|
||||
function setPresence(presence, statusMsg = null) {
|
||||
function setPresence(presence, statusMsg = undefined) {
|
||||
py.callClientCoro(userId, "set_presence", [presence, statusMsg])
|
||||
}
|
||||
|
||||
|
||||
HMenuItem {
|
||||
enabled: firstSyncDone
|
||||
icon.name: "presence"
|
||||
icon.color: theme.controls.presence.online
|
||||
text: qsTr("Online")
|
||||
|
@ -31,8 +29,7 @@ HMenu {
|
|||
}
|
||||
|
||||
HMenuItem {
|
||||
visible: presence
|
||||
enabled: firstSyncDone
|
||||
enabled: presence
|
||||
icon.name: "presence-busy"
|
||||
icon.color: theme.controls.presence.unavailable
|
||||
text: qsTr("Unavailable")
|
||||
|
@ -40,7 +37,6 @@ HMenu {
|
|||
}
|
||||
|
||||
HMenuItem {
|
||||
enabled: firstSyncDone
|
||||
icon.name: "presence-offline"
|
||||
icon.color: theme.controls.presence.offline
|
||||
text: qsTr("Offline")
|
||||
|
@ -48,8 +44,7 @@ HMenu {
|
|||
}
|
||||
|
||||
HMenuItem {
|
||||
visible: presence
|
||||
enabled: firstSyncDone
|
||||
enabled: presence
|
||||
icon.name: "presence-invisible"
|
||||
icon.color: theme.controls.presence.offline
|
||||
text: qsTr("Invisible")
|
||||
|
@ -60,8 +55,7 @@ HMenu {
|
|||
|
||||
HLabeledItem {
|
||||
id: statusMsgLabel
|
||||
visible: presence
|
||||
enabled: firstSyncDone
|
||||
enabled: presence && presence !== "offline"
|
||||
width: parent.width
|
||||
height: visible ? implicitHeight : 0
|
||||
label.text: qsTr("Status message:")
|
||||
|
@ -80,12 +74,14 @@ HMenu {
|
|||
}
|
||||
|
||||
defaultText: statusMsg
|
||||
placeholderText: ! presence ? "Unsupported server" : ""
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
HButton {
|
||||
id: button
|
||||
visible: presence
|
||||
|
||||
icon.name: "apply"
|
||||
icon.color: theme.colors.positiveBackground
|
||||
|
|
|
@ -13,7 +13,12 @@ HTile {
|
|||
tile: account
|
||||
spacing: 0
|
||||
opacity:
|
||||
collapsed ? theme.mainPane.listView.account.collapsedOpacity : 1
|
||||
collapsed ?
|
||||
theme.mainPane.listView.account.collapsedOpacity :
|
||||
|
||||
model.presence == "offline" ?
|
||||
theme.mainPane.listView.offlineOpacity :
|
||||
1
|
||||
|
||||
Behavior on opacity { HNumberAnimation {} }
|
||||
|
||||
|
@ -25,14 +30,14 @@ HTile {
|
|||
radius: theme.mainPane.listView.account.avatarRadius
|
||||
compact: account.compact
|
||||
|
||||
presence: model.presence
|
||||
presence: model.presence_support ? model.presence : ""
|
||||
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
|
||||
HLoader {
|
||||
anchors.fill: parent
|
||||
z: 9998
|
||||
opacity: model.first_sync_done ? 0 : 1
|
||||
opacity: model.connecting ? 1 : 0
|
||||
active: opacity > 0
|
||||
|
||||
sourceComponent: Rectangle {
|
||||
|
@ -157,12 +162,12 @@ HTile {
|
|||
}
|
||||
|
||||
contextMenu: AccountContextMenu {
|
||||
userId: model.id
|
||||
presence: model.presence_support ? model.presence : null
|
||||
statusMsg: model.status_msg
|
||||
|
||||
// Gray out buttons before first sync
|
||||
firstSyncDone: model.first_sync_done
|
||||
userId: model.id
|
||||
presence:
|
||||
model.presence_support || model.presence === "offline" ?
|
||||
model.presence :
|
||||
null
|
||||
statusMsg: model.status_msg
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -15,7 +15,13 @@ HTile {
|
|||
|
||||
contentItem: ContentRow {
|
||||
tile: room
|
||||
opacity: model.left ? theme.mainPane.listView.room.leftRoomOpacity : 1
|
||||
opacity:
|
||||
accountModel.presence === "offline" ?
|
||||
theme.mainPane.listView.offlineOpacity :
|
||||
|
||||
model.left ?
|
||||
theme.mainPane.listView.room.leftRoomOpacity :
|
||||
1
|
||||
|
||||
Behavior on opacity { HNumberAnimation {} }
|
||||
|
||||
|
@ -179,6 +185,10 @@ HTile {
|
|||
readonly property ListModel eventModel:
|
||||
ModelStore.get(model.for_account, model.id, "events")
|
||||
|
||||
// TODO: binding loop
|
||||
readonly property QtObject accountModel:
|
||||
ModelStore.get("accounts").find(model.for_account)
|
||||
|
||||
readonly property QtObject lastEvent:
|
||||
eventModel.count > 0 ? eventModel.get(0) : null
|
||||
}
|
||||
|
|
|
@ -57,6 +57,10 @@ MultiviewPane {
|
|||
}
|
||||
|
||||
|
||||
readonly property QtObject accountModel:
|
||||
ModelStore.get("accounts").find(chat.roomInfo.for_account)
|
||||
|
||||
|
||||
function toggleFocus() {
|
||||
if (roomPane.activeFocus) {
|
||||
if (roomPane.collapse) roomPane.close()
|
||||
|
@ -78,7 +82,9 @@ MultiviewPane {
|
|||
}
|
||||
|
||||
MemberView {}
|
||||
SettingsView {}
|
||||
SettingsView {
|
||||
enabled: accountModel.presence !== "offline"
|
||||
}
|
||||
|
||||
HShortcut {
|
||||
sequences: window.settings.keys.toggleFocusRoomPane
|
||||
|
|
|
@ -316,7 +316,8 @@ mainPane:
|
|||
color mentionBackground: colors.alertBackground
|
||||
|
||||
listView:
|
||||
color background: colors.mediumBackground
|
||||
color background: colors.mediumBackground
|
||||
real offlineOpacity: 0.5
|
||||
|
||||
account:
|
||||
real collapsedOpacity: 0.3
|
||||
|
|
|
@ -325,7 +325,8 @@ mainPane:
|
|||
color mentionBackground: colors.alertBackground
|
||||
|
||||
listView:
|
||||
color background: colors.mediumBackground
|
||||
color background: colors.mediumBackground
|
||||
real offlineOpacity: 0.5
|
||||
|
||||
account:
|
||||
real collapsedOpacity: 0.3
|
||||
|
|
Loading…
Reference in New Issue
Block a user