Add account presences to account context menu
This commit is contained in:
parent
6e202c3e27
commit
0eda6eb278
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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."""
|
||||||
|
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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())
|
||||||
|
|
|
@ -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")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
39
src/icons/thin/user-presence.svg
Normal file
39
src/icons/thin/user-presence.svg
Normal 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 |
Loading…
Reference in New Issue
Block a user