mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-07 22:15:38 -05:00
refactor: start trimming AI bullcrap patterns
This commit is contained in:
@@ -7,477 +7,170 @@ import Quickshell.Bluetooth
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
property bool bluetoothEnabled: false
|
||||
property bool bluetoothAvailable: false
|
||||
readonly property list<BluetoothDevice> bluetoothDevices: []
|
||||
readonly property list<BluetoothDevice> availableDevices: []
|
||||
property bool scanning: false
|
||||
property bool discoverable: false
|
||||
|
||||
property var connectingDevices: ({})
|
||||
|
||||
Component.onCompleted: {
|
||||
refreshBluetoothState()
|
||||
updateDevices()
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Bluetooth
|
||||
readonly property BluetoothAdapter adapter: Bluetooth.defaultAdapter
|
||||
readonly property bool available: adapter !== null
|
||||
readonly property bool enabled: adapter?.enabled ?? false
|
||||
readonly property bool discovering: adapter?.discovering ?? false
|
||||
|
||||
readonly property var devices: {
|
||||
var deviceList = []
|
||||
if (!adapter) return deviceList
|
||||
|
||||
function onDefaultAdapterChanged() {
|
||||
console.log("BluetoothService: Default adapter changed")
|
||||
refreshBluetoothState()
|
||||
updateDevices()
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Bluetooth.defaultAdapter
|
||||
|
||||
function onEnabledChanged() {
|
||||
refreshBluetoothState()
|
||||
updateDevices()
|
||||
}
|
||||
|
||||
function onDiscoveringChanged() {
|
||||
refreshBluetoothState()
|
||||
updateDevices()
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Bluetooth.defaultAdapter ? Bluetooth.defaultAdapter.devices : null
|
||||
|
||||
function onModelReset() {
|
||||
updateDevices()
|
||||
}
|
||||
|
||||
function onItemAdded() {
|
||||
updateDevices()
|
||||
}
|
||||
|
||||
function onItemRemoved() {
|
||||
updateDevices()
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Bluetooth.devices
|
||||
|
||||
function onModelReset() {
|
||||
updateDevices()
|
||||
}
|
||||
|
||||
function onItemAdded() {
|
||||
updateDevices()
|
||||
}
|
||||
|
||||
function onItemRemoved() {
|
||||
updateDevices()
|
||||
}
|
||||
}
|
||||
|
||||
function refreshBluetoothState() {
|
||||
root.bluetoothAvailable = Bluetooth.defaultAdapter !== null
|
||||
root.bluetoothEnabled = Bluetooth.defaultAdapter ? Bluetooth.defaultAdapter.enabled : false
|
||||
root.scanning = Bluetooth.defaultAdapter ? Bluetooth.defaultAdapter.discovering : false
|
||||
root.discoverable = Bluetooth.defaultAdapter ? Bluetooth.defaultAdapter.discoverable : false
|
||||
}
|
||||
|
||||
function updateDevices() {
|
||||
if (!Bluetooth.defaultAdapter) {
|
||||
clearDeviceList(root.bluetoothDevices)
|
||||
clearDeviceList(root.availableDevices)
|
||||
root.bluetoothDevices = []
|
||||
root.availableDevices = []
|
||||
return
|
||||
}
|
||||
|
||||
let newPairedDevices = []
|
||||
let newAvailableDevices = []
|
||||
let allNativeDevices = []
|
||||
|
||||
let adapterDevices = Bluetooth.defaultAdapter.devices
|
||||
if (adapterDevices.values) {
|
||||
allNativeDevices = allNativeDevices.concat(adapterDevices.values)
|
||||
}
|
||||
|
||||
if (Bluetooth.devices.values) {
|
||||
for (let device of Bluetooth.devices.values) {
|
||||
if (!allNativeDevices.some(d => d.address === device.address)) {
|
||||
allNativeDevices.push(device)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let device of allNativeDevices) {
|
||||
if (!device) continue
|
||||
|
||||
let deviceType = getDeviceType(device.name || device.deviceName, device.icon)
|
||||
let displayName = device.name || device.deviceName
|
||||
|
||||
if (!displayName || displayName.startsWith('/org/bluez') || displayName.includes('hci0') || displayName.length < 2) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (device.paired) {
|
||||
let existingDevice = findDeviceInList(root.bluetoothDevices, device.address)
|
||||
if (existingDevice) {
|
||||
updateDeviceData(existingDevice, device, deviceType, displayName)
|
||||
newPairedDevices.push(existingDevice)
|
||||
} else {
|
||||
let newDevice = createBluetoothDevice(device, deviceType, displayName)
|
||||
newPairedDevices.push(newDevice)
|
||||
}
|
||||
} else {
|
||||
if (Bluetooth.defaultAdapter.discovering && isDeviceDiscoverable(device)) {
|
||||
let existingDevice = findDeviceInList(root.availableDevices, device.address)
|
||||
if (existingDevice) {
|
||||
updateDeviceData(existingDevice, device, deviceType, displayName)
|
||||
newAvailableDevices.push(existingDevice)
|
||||
} else {
|
||||
let newDevice = createBluetoothDevice(device, deviceType, displayName)
|
||||
newAvailableDevices.push(newDevice)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanupOldDevices(root.bluetoothDevices, newPairedDevices)
|
||||
cleanupOldDevices(root.availableDevices, newAvailableDevices)
|
||||
|
||||
console.log("BluetoothService: Found", newPairedDevices.length, "paired devices and", newAvailableDevices.length, "available devices")
|
||||
|
||||
root.bluetoothDevices = newPairedDevices
|
||||
root.availableDevices = newAvailableDevices
|
||||
}
|
||||
|
||||
function createBluetoothDevice(nativeDevice, deviceType, displayName) {
|
||||
return deviceComponent.createObject(root, {
|
||||
mac: nativeDevice.address,
|
||||
name: displayName,
|
||||
type: deviceType,
|
||||
paired: nativeDevice.paired,
|
||||
connected: nativeDevice.connected,
|
||||
battery: nativeDevice.batteryAvailable ? Math.round(nativeDevice.battery * 100) : -1,
|
||||
signalStrength: nativeDevice.connected ? "excellent" : "unknown",
|
||||
canPair: !nativeDevice.paired,
|
||||
nativeDevice: nativeDevice,
|
||||
connecting: false,
|
||||
connectionFailed: false
|
||||
})
|
||||
}
|
||||
|
||||
function updateDeviceData(deviceObj, nativeDevice, deviceType, displayName) {
|
||||
deviceObj.name = displayName
|
||||
deviceObj.type = deviceType
|
||||
deviceObj.paired = nativeDevice.paired
|
||||
|
||||
// If device connected state changed, clear connecting/failed states and refresh audio
|
||||
if (deviceObj.connected !== nativeDevice.connected) {
|
||||
deviceObj.connecting = false
|
||||
deviceObj.connectionFailed = false
|
||||
|
||||
// Refresh audio devices when bluetooth audio device connects/disconnects
|
||||
if (deviceType === "headset" || deviceType === "speaker") {
|
||||
Qt.callLater(() => {
|
||||
if (typeof AudioService !== 'undefined') {
|
||||
AudioService.updateDevices()
|
||||
}
|
||||
for (var i = 0; i < adapter.devices.count; i++) {
|
||||
var dev = adapter.devices.get(i)
|
||||
if (dev && dev.ready && _isValidDevice(dev)) {
|
||||
deviceList.push({
|
||||
address: dev.address,
|
||||
name: dev.name || dev.deviceName,
|
||||
paired: dev.paired,
|
||||
connected: dev.connected,
|
||||
iconName: _getDeviceIcon(dev),
|
||||
type: _getDeviceType(dev),
|
||||
batteryLevel: dev.batteryAvailable ? Math.round(dev.battery * 100) : -1,
|
||||
batteryAvailable: dev.batteryAvailable,
|
||||
native: dev
|
||||
})
|
||||
}
|
||||
}
|
||||
return deviceList
|
||||
}
|
||||
|
||||
readonly property var pairedDevices: {
|
||||
return devices.filter(dev => dev.paired)
|
||||
}
|
||||
|
||||
readonly property var availableDevices: {
|
||||
if (!discovering) return []
|
||||
var availableList = []
|
||||
|
||||
deviceObj.connected = nativeDevice.connected
|
||||
deviceObj.battery = nativeDevice.batteryAvailable ? Math.round(nativeDevice.battery * 100) : -1
|
||||
deviceObj.signalStrength = nativeDevice.connected ? "excellent" : "unknown"
|
||||
deviceObj.canPair = !nativeDevice.paired
|
||||
deviceObj.nativeDevice = nativeDevice
|
||||
}
|
||||
|
||||
function findDeviceInList(deviceList, address) {
|
||||
for (let device of deviceList) {
|
||||
if (device.mac === address) {
|
||||
return device
|
||||
if (Bluetooth.devices && Bluetooth.devices.values) {
|
||||
for (var device of Bluetooth.devices.values) {
|
||||
if (device && device.ready && !device.paired && _isValidDevice(device)) {
|
||||
availableList.push({
|
||||
address: device.address,
|
||||
name: device.name || device.deviceName,
|
||||
paired: false,
|
||||
connected: false,
|
||||
iconName: _getDeviceIcon(device),
|
||||
type: _getDeviceType(device),
|
||||
batteryLevel: -1,
|
||||
batteryAvailable: false,
|
||||
native: device
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
return availableList
|
||||
}
|
||||
|
||||
function cleanupOldDevices(oldList, newList) {
|
||||
for (let oldDevice of oldList) {
|
||||
if (!newList.includes(oldDevice)) {
|
||||
oldDevice.destroy()
|
||||
readonly property var allDevicesWithBattery: {
|
||||
return devices.filter(dev => dev.batteryAvailable && dev.batteryLevel >= 0)
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (adapter && adapter.devices) {
|
||||
adapter.devices.itemAdded.connect(devicesChanged)
|
||||
adapter.devices.itemRemoved.connect(devicesChanged)
|
||||
}
|
||||
|
||||
if (Bluetooth.devices) {
|
||||
Bluetooth.devices.itemAdded.connect(devicesChanged)
|
||||
Bluetooth.devices.itemRemoved.connect(devicesChanged)
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Bluetooth
|
||||
function onDefaultAdapterChanged() {
|
||||
if (adapter && adapter.devices) {
|
||||
adapter.devices.itemAdded.connect(devicesChanged)
|
||||
adapter.devices.itemRemoved.connect(devicesChanged)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clearDeviceList(deviceList) {
|
||||
for (let device of deviceList) {
|
||||
device.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
function isDeviceDiscoverable(device) {
|
||||
let displayName = device.name || device.deviceName
|
||||
function _isValidDevice(device) {
|
||||
var displayName = device.name || device.deviceName
|
||||
if (!displayName || displayName.length < 2) return false
|
||||
|
||||
if (displayName.startsWith('/org/bluez') || displayName.includes('hci0')) return false
|
||||
|
||||
let nameLower = displayName.toLowerCase()
|
||||
|
||||
if (nameLower.match(/^[0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}/)) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (displayName.length < 3) return false
|
||||
|
||||
if (nameLower.includes('iphone') || nameLower.includes('ipad') ||
|
||||
nameLower.includes('airpods') || nameLower.includes('samsung') ||
|
||||
nameLower.includes('galaxy') || nameLower.includes('pixel') ||
|
||||
nameLower.includes('headphone') || nameLower.includes('speaker') ||
|
||||
nameLower.includes('mouse') || nameLower.includes('keyboard') ||
|
||||
nameLower.includes('watch') || nameLower.includes('buds') ||
|
||||
nameLower.includes('android')) {
|
||||
return true
|
||||
}
|
||||
|
||||
return displayName.length >= 4 && !displayName.match(/^[A-Z0-9_-]+$/)
|
||||
return displayName.length >= 3
|
||||
}
|
||||
|
||||
function getDeviceType(name, icon) {
|
||||
if (!name && !icon) return "bluetooth"
|
||||
|
||||
let nameLower = (name || "").toLowerCase()
|
||||
let iconLower = (icon || "").toLowerCase()
|
||||
|
||||
if (iconLower.includes("audio") || iconLower.includes("headset") || iconLower.includes("headphone") ||
|
||||
nameLower.includes("headphone") || nameLower.includes("airpod") || nameLower.includes("headset") ||
|
||||
nameLower.includes("arctis") || nameLower.includes("audio")) return "headset"
|
||||
else if (iconLower.includes("input-mouse") || nameLower.includes("mouse")) return "mouse"
|
||||
else if (iconLower.includes("input-keyboard") || nameLower.includes("keyboard")) return "keyboard"
|
||||
else if (iconLower.includes("phone") || nameLower.includes("phone") || nameLower.includes("iphone") ||
|
||||
nameLower.includes("samsung") || nameLower.includes("android")) return "phone"
|
||||
else if (iconLower.includes("watch") || nameLower.includes("watch")) return "watch"
|
||||
else if (iconLower.includes("audio-speakers") || nameLower.includes("speaker")) return "speaker"
|
||||
else if (iconLower.includes("video-display") || nameLower.includes("tv") || nameLower.includes("display")) return "tv"
|
||||
function _getDeviceIcon(device) {
|
||||
var name = (device.name || device.deviceName || "").toLowerCase()
|
||||
var icon = (device.icon || "").toLowerCase()
|
||||
|
||||
if (icon.includes("headset") || icon.includes("audio") || name.includes("headphone") ||
|
||||
name.includes("airpod") || name.includes("headset") || name.includes("arctis")) return "headset"
|
||||
if (icon.includes("mouse") || name.includes("mouse")) return "mouse"
|
||||
if (icon.includes("keyboard") || name.includes("keyboard")) return "keyboard"
|
||||
if (icon.includes("phone") || name.includes("phone") || name.includes("iphone") ||
|
||||
name.includes("android") || name.includes("samsung")) return "smartphone"
|
||||
if (icon.includes("watch") || name.includes("watch")) return "watch"
|
||||
if (icon.includes("speaker") || name.includes("speaker")) return "speaker"
|
||||
if (icon.includes("display") || name.includes("tv")) return "tv"
|
||||
return "bluetooth"
|
||||
}
|
||||
|
||||
function startDiscovery() {
|
||||
if (Bluetooth.defaultAdapter && Bluetooth.defaultAdapter.enabled) {
|
||||
Bluetooth.defaultAdapter.discovering = true
|
||||
updateDevices()
|
||||
}
|
||||
function _getDeviceType(device) {
|
||||
var name = (device.name || device.deviceName || "").toLowerCase()
|
||||
var icon = (device.icon || "").toLowerCase()
|
||||
|
||||
if (icon.includes("headset") || icon.includes("audio") || name.includes("headphone") ||
|
||||
name.includes("airpod") || name.includes("headset") || name.includes("arctis")) return "headset"
|
||||
if (icon.includes("mouse") || name.includes("mouse")) return "mouse"
|
||||
if (icon.includes("keyboard") || name.includes("keyboard")) return "keyboard"
|
||||
if (icon.includes("phone") || name.includes("phone") || name.includes("iphone") ||
|
||||
name.includes("android") || name.includes("samsung")) return "phone"
|
||||
if (icon.includes("watch") || name.includes("watch")) return "watch"
|
||||
if (icon.includes("speaker") || name.includes("speaker")) return "speaker"
|
||||
if (icon.includes("display") || name.includes("tv")) return "tv"
|
||||
return "bluetooth"
|
||||
}
|
||||
|
||||
function stopDiscovery() {
|
||||
if (Bluetooth.defaultAdapter) {
|
||||
Bluetooth.defaultAdapter.discovering = false
|
||||
updateDevices()
|
||||
}
|
||||
function toggleAdapter() {
|
||||
if (adapter) adapter.enabled = !adapter.enabled
|
||||
}
|
||||
|
||||
function pairDevice(mac) {
|
||||
console.log("Pairing device:", mac)
|
||||
let device = findDeviceByMac(mac)
|
||||
function startScan() {
|
||||
if (adapter) adapter.discovering = true
|
||||
}
|
||||
|
||||
function stopScan() {
|
||||
if (adapter) adapter.discovering = false
|
||||
}
|
||||
|
||||
function connect(address) {
|
||||
var device = _findDevice(address)
|
||||
if (device) device.connect()
|
||||
}
|
||||
|
||||
function disconnect(address) {
|
||||
var device = _findDevice(address)
|
||||
if (device) device.disconnect()
|
||||
}
|
||||
|
||||
function pair(address) {
|
||||
var device = _findDevice(address)
|
||||
if (device) device.pair()
|
||||
}
|
||||
|
||||
function forget(address) {
|
||||
var device = _findDevice(address)
|
||||
if (device) device.forget()
|
||||
}
|
||||
|
||||
function toggle(address) {
|
||||
var device = _findDevice(address)
|
||||
if (device) {
|
||||
device.pair()
|
||||
if (device.connected) device.disconnect()
|
||||
else device.connect()
|
||||
}
|
||||
}
|
||||
|
||||
function connectDevice(mac) {
|
||||
console.log("Connecting to device:", mac)
|
||||
let device = findDeviceByMac(mac)
|
||||
if (device) {
|
||||
device.connect()
|
||||
}
|
||||
}
|
||||
|
||||
function removeDevice(mac) {
|
||||
console.log("Removing device:", mac)
|
||||
let device = findDeviceByMac(mac)
|
||||
if (device) {
|
||||
device.forget()
|
||||
}
|
||||
}
|
||||
|
||||
function toggleBluetoothDevice(mac) {
|
||||
let typedDevice = findDeviceInList(root.bluetoothDevices, mac)
|
||||
if (!typedDevice) {
|
||||
typedDevice = findDeviceInList(root.availableDevices, mac)
|
||||
}
|
||||
|
||||
if (typedDevice && typedDevice.nativeDevice) {
|
||||
if (typedDevice.connected) {
|
||||
console.log("Disconnecting device:", mac)
|
||||
typedDevice.connecting = false
|
||||
typedDevice.connectionFailed = false
|
||||
typedDevice.nativeDevice.connected = false
|
||||
} else {
|
||||
console.log("Connecting to device:", mac)
|
||||
typedDevice.connecting = true
|
||||
typedDevice.connectionFailed = false
|
||||
|
||||
// Set a timeout to handle connection failure
|
||||
Qt.callLater(() => {
|
||||
connectionTimeout.deviceMac = mac
|
||||
connectionTimeout.start()
|
||||
})
|
||||
|
||||
typedDevice.nativeDevice.connected = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function toggleBluetooth() {
|
||||
if (Bluetooth.defaultAdapter) {
|
||||
Bluetooth.defaultAdapter.enabled = !Bluetooth.defaultAdapter.enabled
|
||||
}
|
||||
}
|
||||
|
||||
function findDeviceByMac(mac) {
|
||||
let typedDevice = findDeviceInList(root.bluetoothDevices, mac)
|
||||
if (typedDevice && typedDevice.nativeDevice) {
|
||||
return typedDevice.nativeDevice
|
||||
}
|
||||
|
||||
typedDevice = findDeviceInList(root.availableDevices, mac)
|
||||
if (typedDevice && typedDevice.nativeDevice) {
|
||||
return typedDevice.nativeDevice
|
||||
}
|
||||
|
||||
if (Bluetooth.defaultAdapter) {
|
||||
let adapterDevices = Bluetooth.defaultAdapter.devices
|
||||
if (adapterDevices.values) {
|
||||
for (let device of adapterDevices.values) {
|
||||
if (device && device.address === mac) {
|
||||
return device
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Bluetooth.devices.values) {
|
||||
for (let device of Bluetooth.devices.values) {
|
||||
if (device && device.address === mac) {
|
||||
return device
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
Timer {
|
||||
id: bluetoothMonitorTimer
|
||||
interval: 2000
|
||||
running: false
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
updateDevices()
|
||||
}
|
||||
}
|
||||
|
||||
function enableMonitoring(enabled) {
|
||||
bluetoothMonitorTimer.running = enabled
|
||||
if (enabled) {
|
||||
refreshBluetoothState()
|
||||
updateDevices()
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: bluetoothStateRefreshTimer
|
||||
interval: 5000
|
||||
running: true
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
refreshBluetoothState()
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: connectionTimeout
|
||||
interval: 10000 // 10 second timeout
|
||||
running: false
|
||||
repeat: false
|
||||
|
||||
property string deviceMac: ""
|
||||
|
||||
onTriggered: {
|
||||
if (deviceMac) {
|
||||
let typedDevice = findDeviceInList(root.bluetoothDevices, deviceMac)
|
||||
if (!typedDevice) {
|
||||
typedDevice = findDeviceInList(root.availableDevices, deviceMac)
|
||||
}
|
||||
|
||||
if (typedDevice && typedDevice.connecting && !typedDevice.connected) {
|
||||
console.log("Connection timeout for device:", deviceMac)
|
||||
typedDevice.connecting = false
|
||||
typedDevice.connectionFailed = true
|
||||
|
||||
// Clear failure state after 3 seconds
|
||||
Qt.callLater(() => {
|
||||
clearFailureTimer.deviceMac = deviceMac
|
||||
clearFailureTimer.start()
|
||||
})
|
||||
}
|
||||
deviceMac = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: clearFailureTimer
|
||||
interval: 3000
|
||||
running: false
|
||||
repeat: false
|
||||
|
||||
property string deviceMac: ""
|
||||
|
||||
onTriggered: {
|
||||
if (deviceMac) {
|
||||
let typedDevice = findDeviceInList(root.bluetoothDevices, deviceMac)
|
||||
if (!typedDevice) {
|
||||
typedDevice = findDeviceInList(root.availableDevices, deviceMac)
|
||||
}
|
||||
|
||||
if (typedDevice) {
|
||||
typedDevice.connectionFailed = false
|
||||
}
|
||||
deviceMac = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component BluetoothDevice: QtObject {
|
||||
required property string mac
|
||||
required property string name
|
||||
required property string type
|
||||
required property bool paired
|
||||
required property bool connected
|
||||
required property int battery
|
||||
required property string signalStrength
|
||||
required property bool canPair
|
||||
required property var nativeDevice // Reference to native Quickshell device
|
||||
|
||||
property bool connecting: false
|
||||
property bool connectionFailed: false
|
||||
|
||||
readonly property string displayName: name
|
||||
readonly property bool batteryAvailable: battery >= 0
|
||||
readonly property string connectionStatus: {
|
||||
if (connecting) return "Connecting..."
|
||||
if (connectionFailed) return "Connection Failed"
|
||||
if (connected) return "Connected"
|
||||
return "Disconnected"
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: deviceComponent
|
||||
BluetoothDevice {}
|
||||
function _findDevice(address) {
|
||||
if (!adapter) return null
|
||||
return adapter.devices.values.find(d => d.address === address) ||
|
||||
(Bluetooth.devices ? Bluetooth.devices.values.find(d => d.address === address) : null)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user