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

View File

@ -237,15 +237,23 @@ class MatrixClient(nio.AsyncClient):
await super().login( await super().login(
password, device_name or self.default_device_name(), password, device_name or self.default_device_name(),
) )
self.start_task = asyncio.ensure_future(self._start()) 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.""" """Login to the server using an existing access token."""
response = nio.LoginResponse(user_id, device_id, token) response = nio.LoginResponse(user_id, device_id, token)
await self.receive_response(response) await self.receive_response(response)
await self.set_presence(presence)
self.start_task = asyncio.ensure_future(self._start()) self.start_task = asyncio.ensure_future(self._start())
@ -1209,6 +1217,16 @@ class MatrixClient(nio.AsyncClient):
await self.set_avatar(mxc) 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: async def import_keys(self, infile: str, passphrase: str) -> None:
"""Import decryption keys from a file, then retry decrypting events.""" """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 offline = auto() # can mean offline, invisible or unknwon
unavailable = auto() unavailable = auto()
online = auto() online = auto()
invisible = auto()
def __lt__(self, other: "Presence.State") -> bool: def __lt__(self, other: "Presence.State") -> bool:
order = [self.online, self.unavailable, self.offline] order = [
self.online,
self.unavailable,
self.invisible,
self.offline,
]
return ( return (
order.index(self) # type: ignore order.index(self) # type: ignore
@ -45,9 +51,9 @@ class Presence():
order.index(other) # type: ignore order.index(other) # type: ignore
) )
last_active_ago: int = -1
status_msg: str = "" status_msg: str = ""
presence: State = State.offline presence: State = State.offline
last_active_ago: int = -1
currently_active: bool = False currently_active: bool = False
@ -67,6 +73,8 @@ class Account(ModelItem):
local_unreads: bool = False local_unreads: bool = False
local_highlights: bool = False local_highlights: bool = False
presence: Presence.State = Presence.State.offline
def __lt__(self, other: "Account") -> bool: def __lt__(self, other: "Account") -> bool:
"""Sort by order, then by user ID.""" """Sort by order, then by user ID."""
return (self.order, self.id.lower()) < (other.order, other.id.lower()) return (self.order, self.id.lower()) < (other.order, other.id.lower())

View File

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

View File

@ -1,11 +1,19 @@
// SPDX-License-Identifier: LGPL-3.0-or-later // SPDX-License-Identifier: LGPL-3.0-or-later
import QtQuick 2.12 import QtQuick 2.12
import QtQuick.Controls 2.12
import Clipboard 0.1 import Clipboard 0.1
import "../Base" import "../Base"
HMenu { HMenu {
property string userId property string userId
property string presence
property bool firstSyncDone
function setPresence(presence) {
py.callClientCoro(userId, "set_presence", [presence])
}
HMenuItem { HMenuItem {
@ -36,4 +44,38 @@ HMenu {
popup: "Popups/SignOutPopup.qml" popup: "Popups/SignOutPopup.qml"
properties: { "userId": userId } 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 radius: theme.mainPane.listView.account.avatarRadius
compact: account.compact compact: account.compact
// XXX presence: model.presence
presence: model.first_sync_done ? "online" : ""
Layout.alignment: Qt.AlignCenter 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 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