Add buttons to Save/cancel power level changes
This commit is contained in:
parent
1adfa9f4a2
commit
6ff3cc5f39
|
@ -191,6 +191,9 @@ class MatrixClient(nio.AsyncClient):
|
||||||
self.loaded_once_rooms: Set[str] = set() # {room_id}
|
self.loaded_once_rooms: Set[str] = set() # {room_id}
|
||||||
self.cleared_events_rooms: Set[str] = set() # {room_id}
|
self.cleared_events_rooms: Set[str] = set() # {room_id}
|
||||||
|
|
||||||
|
# {room_id: <m.room.power_levels event content dict>}
|
||||||
|
self.power_levels_content: Dict[str, Dict[str, Any]] = {}
|
||||||
|
|
||||||
self.nio_callbacks = NioCallbacks(self)
|
self.nio_callbacks = NioCallbacks(self)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1120,6 +1123,20 @@ class MatrixClient(nio.AsyncClient):
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
async def room_set_member_power(
|
||||||
|
self, room_id: str, user_id: str, level: int,
|
||||||
|
) -> None:
|
||||||
|
"""Set a room member's power level."""
|
||||||
|
|
||||||
|
while room_id not in self.power_levels_content:
|
||||||
|
await asyncio.sleep(0.2)
|
||||||
|
|
||||||
|
content = deepcopy(self.power_levels_content[room_id])
|
||||||
|
content.setdefault("users", {})[user_id] = level
|
||||||
|
|
||||||
|
await self.room_put_state(room_id, "m.room.power_levels", content)
|
||||||
|
|
||||||
|
|
||||||
async def room_typing(
|
async def room_typing(
|
||||||
self, room_id: str, typing_state: bool = True, timeout: int = 5000,
|
self, room_id: str, typing_state: bool = True, timeout: int = 5000,
|
||||||
):
|
):
|
||||||
|
|
|
@ -313,6 +313,8 @@ class NioCallbacks:
|
||||||
async def onPowerLevelsEvent(
|
async def onPowerLevelsEvent(
|
||||||
self, room: nio.MatrixRoom, ev: nio.PowerLevelsEvent,
|
self, room: nio.MatrixRoom, ev: nio.PowerLevelsEvent,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
self.client.power_levels_content[room.room_id] = ev.source["content"]
|
||||||
|
|
||||||
co = "%1 changed the room's permissions" # TODO: improve
|
co = "%1 changed the room's permissions" # TODO: improve
|
||||||
await self.client.register_nio_event(room, ev, content=co)
|
await self.client.register_nio_event(room, ev, content=co)
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,9 @@ AutoDirectionLayout {
|
||||||
|
|
||||||
readonly property alias changed: field.changed
|
readonly property alias changed: field.changed
|
||||||
readonly property int level: Math.min(100, parseInt(field.text || "0", 10))
|
readonly property int level: Math.min(100, parseInt(field.text || "0", 10))
|
||||||
|
readonly property alias fieldFocused: field.activeFocus
|
||||||
|
|
||||||
|
signal accepted()
|
||||||
|
|
||||||
function reset() { field.reset() }
|
function reset() { field.reset() }
|
||||||
|
|
||||||
|
@ -28,6 +31,7 @@ AutoDirectionLayout {
|
||||||
maximumLength: control.level < 0 ? 16 : 3
|
maximumLength: control.level < 0 ? 16 : 3
|
||||||
defaultText: String(control.defaultLevel)
|
defaultText: String(control.defaultLevel)
|
||||||
|
|
||||||
|
onAccepted: control.accepted()
|
||||||
onActiveFocusChanged:
|
onActiveFocusChanged:
|
||||||
if (! activeFocus && parseInt(text || "0", 10) > 100)
|
if (! activeFocus && parseInt(text || "0", 10) > 100)
|
||||||
text = 100
|
text = 100
|
||||||
|
|
|
@ -4,21 +4,27 @@ import QtQuick 2.12
|
||||||
import QtQuick.Layouts 1.12
|
import QtQuick.Layouts 1.12
|
||||||
import "../../../.."
|
import "../../../.."
|
||||||
import "../../../../Base"
|
import "../../../../Base"
|
||||||
|
import "../../../../Base/Buttons"
|
||||||
|
import "../../../../PythonBridge"
|
||||||
|
|
||||||
HListView {
|
HListView {
|
||||||
id: profile
|
id: root
|
||||||
|
|
||||||
property string userId
|
property string userId
|
||||||
property string roomId
|
property string roomId
|
||||||
property QtObject member // RoomMember model item
|
property QtObject member // RoomMember model item
|
||||||
property HStackView stackView
|
property HStackView stackView
|
||||||
|
|
||||||
|
property bool powerLevelFieldFocused: false
|
||||||
|
|
||||||
|
property Future setPowerFuture: null
|
||||||
|
|
||||||
function loadDevices() {
|
function loadDevices() {
|
||||||
py.callClientCoro(userId, "member_devices", [member.id], devices => {
|
py.callClientCoro(userId, "member_devices", [member.id], devices => {
|
||||||
profile.model.clear()
|
root.model.clear()
|
||||||
|
|
||||||
for (const device of devices)
|
for (const device of devices)
|
||||||
profile.model.append(device)
|
root.model.append(device)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,23 +33,23 @@ HListView {
|
||||||
bottomMargin: theme.spacing
|
bottomMargin: theme.spacing
|
||||||
model: ListModel {}
|
model: ListModel {}
|
||||||
delegate: MemberDeviceDelegate {
|
delegate: MemberDeviceDelegate {
|
||||||
width: profile.width
|
width: root.width
|
||||||
userId: profile.userId
|
userId: root.userId
|
||||||
deviceOwner: member.id
|
deviceOwner: member.id
|
||||||
deviceOwnerDisplayName: member.display_name
|
deviceOwnerDisplayName: member.display_name
|
||||||
stackView: profile.stackView
|
stackView: root.stackView
|
||||||
|
|
||||||
onTrustSet: trust => profile.loadDevices()
|
onTrustSet: trust => root.loadDevices()
|
||||||
}
|
}
|
||||||
|
|
||||||
section.property: "type"
|
section.property: "type"
|
||||||
section.delegate: MemberDeviceSection {
|
section.delegate: MemberDeviceSection {
|
||||||
width: profile.width
|
width: root.width
|
||||||
}
|
}
|
||||||
|
|
||||||
header: HColumnLayout {
|
header: HColumnLayout {
|
||||||
x: theme.spacing
|
x: theme.spacing
|
||||||
width: profile.width - x * 2
|
width: root.width - x * 2
|
||||||
spacing: theme.spacing * 1.5
|
spacing: theme.spacing * 1.5
|
||||||
|
|
||||||
HUserAvatar {
|
HUserAvatar {
|
||||||
|
@ -64,7 +70,7 @@ HListView {
|
||||||
circle: true
|
circle: true
|
||||||
icon.name: "close-view"
|
icon.name: "close-view"
|
||||||
iconItem.small: true
|
iconItem.small: true
|
||||||
onClicked: profile.stackView.pop()
|
onClicked: root.stackView.pop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,25 +159,78 @@ HListView {
|
||||||
}
|
}
|
||||||
|
|
||||||
HLabeledItem {
|
HLabeledItem {
|
||||||
id: powerLevelItem
|
id: powerLevel
|
||||||
label.text: qsTr("Power level:")
|
label.text: qsTr("Power level:")
|
||||||
label.horizontalAlignment: Qt.AlignHCenter
|
label.horizontalAlignment: Qt.AlignHCenter
|
||||||
|
|
||||||
Layout.preferredWidth: parent.width
|
Layout.preferredWidth: parent.width
|
||||||
Layout.bottomMargin: theme.spacing
|
|
||||||
|
|
||||||
PowerLevelControl {
|
PowerLevelControl {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
defaultLevel: member.power_level
|
defaultLevel: member.power_level
|
||||||
rowSpacing: powerLevelItem.spacing
|
rowSpacing: powerLevel.spacing
|
||||||
|
onAccepted: applyButton.clicked()
|
||||||
|
onFieldFocusedChanged:
|
||||||
|
root.powerLevelFieldFocused = fieldFocused
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AutoDirectionLayout {
|
||||||
|
visible: scale > 0
|
||||||
|
id: buttonsLayout
|
||||||
|
scale: powerLevel.item.changed ? 1 : 0
|
||||||
|
rowSpacing: powerLevel.spacing
|
||||||
|
|
||||||
|
Layout.preferredWidth: parent.width
|
||||||
|
Layout.preferredHeight: implicitHeight * scale
|
||||||
|
Layout.topMargin: -theme.spacing
|
||||||
|
|
||||||
|
Behavior on scale { HNumberAnimation {} }
|
||||||
|
|
||||||
|
HSpacer {}
|
||||||
|
|
||||||
|
ApplyButton {
|
||||||
|
id: applyButton
|
||||||
|
loading: setPowerFuture !== null
|
||||||
|
onClicked: {
|
||||||
|
setPowerFuture = py.callClientCoro(
|
||||||
|
userId,
|
||||||
|
"room_set_member_power",
|
||||||
|
[roomId, member.id, powerLevel.item.level],
|
||||||
|
() => { setPowerFuture = null }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Layout.fillWidth: false
|
||||||
|
Layout.alignment: Qt.AlignCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
CancelButton {
|
||||||
|
onClicked: {
|
||||||
|
setPowerFuture.cancel()
|
||||||
|
setPowerFuture = null
|
||||||
|
powerLevel.item.reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
Layout.fillWidth: false
|
||||||
|
Layout.alignment: Qt.AlignCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
HSpacer {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
// This item is just to have some spacing at the bottom of header
|
||||||
|
visible: root.count > 0
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: loadDevices()
|
Component.onCompleted: loadDevices()
|
||||||
|
Component.onDestruction: if (setPowerFuture) setPowerFuture.cancel()
|
||||||
|
|
||||||
Keys.onEnterPressed: Keys.onReturnPressed(event)
|
Keys.onEnterPressed: Keys.onReturnPressed(event)
|
||||||
Keys.onReturnPressed: {
|
Keys.onReturnPressed: if (! powerLevelFieldFocused && currentItem) {
|
||||||
currentItem.leftClicked()
|
currentItem.leftClicked()
|
||||||
currentItem.clicked()
|
currentItem.clicked()
|
||||||
}
|
}
|
||||||
|
@ -181,7 +240,7 @@ HListView {
|
||||||
target: py.eventHandlers
|
target: py.eventHandlers
|
||||||
|
|
||||||
function onDeviceUpdateSignal(forAccount) {
|
function onDeviceUpdateSignal(forAccount) {
|
||||||
if (forAccount === profile.userId) profile.loadDevices()
|
if (forAccount === root.userId) root.loadDevices()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user