Add buttons to Save/cancel power level changes

This commit is contained in:
miruka 2020-07-12 18:48:34 -04:00
parent 1adfa9f4a2
commit 6ff3cc5f39
4 changed files with 97 additions and 15 deletions

View File

@ -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,
): ):

View File

@ -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)

View File

@ -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

View File

@ -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()
} }
} }
} }