Add account presences to account context menu

This commit is contained in:
vslg 2020-07-02 00:27:50 -03:00 committed by miruka
parent 6e202c3e27
commit 0eda6eb278
7 changed files with 128 additions and 13 deletions

View File

@ -18,14 +18,11 @@ from .matrix_client import MatrixClient
from .media_cache import MediaCache
from .models import SyncId
from .models.filters import FieldSubstringFilter
from .models.items import Account
from .models.items import Account, Presence
from .models.model import Model
from .models.model_store import ModelStore
from .user_files import Accounts, History, Theme, UISettings, UIState
if TYPE_CHECKING:
from .models.items import Presence
# Logging configuration
log.getLogger().setLevel(log.INFO)
nio.logger_group.level = nio.log.logbook.ERROR
@ -112,7 +109,7 @@ class Backend:
self.media_cache: MediaCache = MediaCache(self, cache_dir)
self.presences: Dict[str, "Presence"] = {}
self.presences: Dict[str, Presence] = {}
def __repr__(self) -> str:
@ -154,7 +151,12 @@ class Backend:
) + 1
self.clients[client.user_id] = client
self.models["accounts"][client.user_id] = Account(client.user_id,order)
self.models["accounts"][client.user_id] = Account(
client.user_id,
order,
presence = Presence.State.online,
)
return client.user_id
@ -165,6 +167,7 @@ class Backend:
device_id: str,
homeserver: str = "https://matrix.org",
order: int = -1,
presence: str = "online",
) -> None:
"""Create and register a `MatrixClient` with known account details."""
@ -176,7 +179,7 @@ class Backend:
self.clients[user_id] = client
self.models["accounts"][user_id] = Account(user_id, order)
await client.resume(user_id=user_id, token=token, device_id=device_id)
await client.resume(user_id, token, device_id, presence)
async def load_saved_accounts(self) -> List[str]:
@ -189,6 +192,7 @@ class Backend:
device_id = info["device_id"],
homeserver = info["homeserver"],
order = info.get("order", -1),
presence = info.get("presence", "online"),
)
return user_id

View File

@ -237,15 +237,23 @@ class MatrixClient(nio.AsyncClient):
await super().login(
password, device_name or self.default_device_name(),
)
self.start_task = asyncio.ensure_future(self._start())
async def resume(self, user_id: str, token: str, device_id: str) -> None:
async def resume(
self,
user_id: str,
token: str,
device_id: str,
presence: str = "online",
) -> None:
"""Login to the server using an existing access token."""
response = nio.LoginResponse(user_id, device_id, token)
await self.receive_response(response)
await self.set_presence(presence)
self.start_task = asyncio.ensure_future(self._start())
@ -1209,6 +1217,16 @@ class MatrixClient(nio.AsyncClient):
await self.set_avatar(mxc)
async def set_presence(self, presence: str) -> None:
"""Set presence state for this account."""
await super().set_presence("offline" if presence == "invisible"
else presence)
self.models["accounts"][self.user].presence = Presence.State(presence)
await self.backend.saved_accounts.add(self.user)
async def import_keys(self, infile: str, passphrase: str) -> None:
"""Import decryption keys from a file, then retry decrypting events."""

View File

@ -35,9 +35,15 @@ class Presence():
offline = auto() # can mean offline, invisible or unknwon
unavailable = auto()
online = auto()
invisible = auto()
def __lt__(self, other: "Presence.State") -> bool:
order = [self.online, self.unavailable, self.offline]
order = [
self.online,
self.unavailable,
self.invisible,
self.offline,
]
return (
order.index(self) # type: ignore
@ -45,9 +51,9 @@ class Presence():
order.index(other) # type: ignore
)
last_active_ago: int = -1
status_msg: str = ""
presence: State = State.offline
last_active_ago: int = -1
currently_active: bool = False
@ -67,6 +73,8 @@ class Account(ModelItem):
local_unreads: bool = False
local_highlights: bool = False
presence: Presence.State = Presence.State.offline
def __lt__(self, other: "Account") -> bool:
"""Sort by order, then by user ID."""
return (self.order, self.id.lower()) < (other.order, other.id.lower())

View File

@ -192,6 +192,7 @@ class Accounts(JSONDataFile):
"token": client.access_token,
"device_id": client.device_id,
"enabled": True,
"presence": client._presence or "online",
"order": max([
account.get("order", i)
for i, account in enumerate(saved.values())

View File

@ -1,11 +1,19 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
import QtQuick 2.12
import QtQuick.Controls 2.12
import Clipboard 0.1
import "../Base"
HMenu {
property string userId
property string presence
property bool firstSyncDone
function setPresence(presence) {
py.callClientCoro(userId, "set_presence", [presence])
}
HMenuItem {
@ -36,4 +44,38 @@ HMenu {
popup: "Popups/SignOutPopup.qml"
properties: { "userId": userId }
}
HMenuSeparator { }
HMenuItem {
enabled: presence !== "online" && firstSyncDone
icon.name: "user-presence"
icon.color: theme.controls.presence.online
text: qsTr("Online")
onTriggered: setPresence("online")
}
HMenuItem {
enabled: presence !== "unavailable" && firstSyncDone
icon.name: "user-presence"
icon.color: theme.controls.presence.unavailable
text: qsTr("Unavailable")
onTriggered: setPresence("unavailable")
}
HMenuItem {
enabled: presence !== "invisible" && firstSyncDone
icon.name: "user-presence"
icon.color: theme.controls.presence.offline
text: qsTr("Invisible")
onTriggered: setPresence("invisible")
}
HMenuItem {
enabled: presence !== "offline" && firstSyncDone
icon.name: "user-presence"
icon.color: theme.controls.presence.offline
text: qsTr("Offline")
onTriggered: setPresence("offline")
}
}

View File

@ -25,8 +25,7 @@ HTile {
radius: theme.mainPane.listView.account.avatarRadius
compact: account.compact
// XXX
presence: model.first_sync_done ? "online" : ""
presence: model.presence
Layout.alignment: Qt.AlignCenter
@ -136,7 +135,11 @@ HTile {
}
}
contextMenu: AccountContextMenu { userId: model.id }
contextMenu: AccountContextMenu {
userId: model.id
presence: model.presence
firstSyncDone: model.first_sync_done
}
property bool enableKeybinds: false

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 258.75 258.75" style="enable-background:new 0 0 258.75 258.75;" xml:space="preserve">
<g>
<circle cx="129.375" cy="60" r="60"/>
<path d="M129.375,150c-60.061,0-108.75,48.689-108.75,108.75h217.5C238.125,198.689,189.436,150,129.375,150z"/>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 706 B