mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-06 05:25:41 -05:00
Updates to scrolling logic
This commit is contained in:
@@ -433,27 +433,20 @@ DankModal {
|
|||||||
ListView {
|
ListView {
|
||||||
id: clipboardListView
|
id: clipboardListView
|
||||||
|
|
||||||
property real wheelMultiplier: 1.8
|
|
||||||
property int wheelBaseStep: 160
|
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: Theme.spacingS
|
anchors.margins: Theme.spacingS
|
||||||
clip: true
|
clip: true
|
||||||
model: filteredClipboardModel
|
model: filteredClipboardModel
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
WheelHandler {
|
// Enhanced native kinetic scrolling - faster for both touchpad and mouse
|
||||||
target: null
|
interactive: true
|
||||||
onWheel: (ev) => {
|
flickDeceleration: 1000 // Lower = more momentum, longer scrolling
|
||||||
let dy = ev.pixelDelta.y !== 0 ? ev.pixelDelta.y : (ev.angleDelta.y / 120) * clipboardListView.wheelBaseStep;
|
maximumFlickVelocity: 8000 // Higher = faster maximum scroll speed
|
||||||
if (ev.inverted)
|
boundsBehavior: Flickable.DragAndOvershootBounds
|
||||||
dy = -dy;
|
boundsMovement: Flickable.FollowBoundsBehavior
|
||||||
|
pressDelay: 0
|
||||||
const maxY = Math.max(0, clipboardListView.contentHeight - clipboardListView.height);
|
flickableDirection: Flickable.VerticalFlick
|
||||||
clipboardListView.contentY = Math.max(0, Math.min(maxY, clipboardListView.contentY - dy * clipboardListView.wheelMultiplier));
|
|
||||||
ev.accepted = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: "No clipboard entries found"
|
text: "No clipboard entries found"
|
||||||
|
|||||||
@@ -203,24 +203,14 @@ DankModal {
|
|||||||
ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded }
|
ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded }
|
||||||
ScrollBar.horizontal: ScrollBar { policy: ScrollBar.AlwaysOff }
|
ScrollBar.horizontal: ScrollBar { policy: ScrollBar.AlwaysOff }
|
||||||
|
|
||||||
property real wheelMultiplier: 1.8
|
// Enhanced native kinetic scrolling - faster for both touchpad and mouse
|
||||||
property int wheelBaseStep: 160
|
interactive: true
|
||||||
|
flickDeceleration: 1000 // Lower = more momentum, longer scrolling
|
||||||
WheelHandler {
|
maximumFlickVelocity: 8000 // Higher = faster maximum scroll speed
|
||||||
target: null
|
boundsBehavior: Flickable.DragAndOvershootBounds
|
||||||
onWheel: (ev) => {
|
boundsMovement: Flickable.FollowBoundsBehavior
|
||||||
let dy = ev.pixelDelta.y !== 0
|
pressDelay: 0
|
||||||
? ev.pixelDelta.y
|
flickableDirection: Flickable.VerticalFlick
|
||||||
: (ev.angleDelta.y / 120) * fileGrid.wheelBaseStep;
|
|
||||||
if (ev.inverted) dy = -dy;
|
|
||||||
|
|
||||||
const maxY = Math.max(0, fileGrid.contentHeight - fileGrid.height);
|
|
||||||
fileGrid.contentY = Math.max(0, Math.min(maxY,
|
|
||||||
fileGrid.contentY - dy * fileGrid.wheelMultiplier));
|
|
||||||
|
|
||||||
ev.accepted = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delegate: StyledRect {
|
delegate: StyledRect {
|
||||||
id: delegateRoot
|
id: delegateRoot
|
||||||
|
|||||||
@@ -90,27 +90,20 @@ DankModal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Flickable {
|
Flickable {
|
||||||
property real wheelMultiplier: 1.8
|
|
||||||
property int wheelBaseStep: 160
|
|
||||||
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: parent.height - 140
|
height: parent.height - 140
|
||||||
clip: true
|
clip: true
|
||||||
contentWidth: width
|
contentWidth: width
|
||||||
contentHeight: detailsRect.height
|
contentHeight: detailsRect.height
|
||||||
|
|
||||||
WheelHandler {
|
// Enhanced native kinetic scrolling - faster for both touchpad and mouse
|
||||||
target: null
|
interactive: true
|
||||||
onWheel: (ev) => {
|
flickDeceleration: 1000 // Lower = more momentum, longer scrolling
|
||||||
let dy = ev.pixelDelta.y !== 0 ? ev.pixelDelta.y : (ev.angleDelta.y / 120) * parent.wheelBaseStep;
|
maximumFlickVelocity: 8000 // Higher = faster maximum scroll speed
|
||||||
if (ev.inverted)
|
boundsBehavior: Flickable.DragAndOvershootBounds
|
||||||
dy = -dy;
|
boundsMovement: Flickable.FollowBoundsBehavior
|
||||||
|
pressDelay: 0
|
||||||
const maxY = Math.max(0, parent.contentHeight - parent.height);
|
flickableDirection: Flickable.VerticalFlick
|
||||||
parent.contentY = Math.max(0, Math.min(maxY, parent.contentY - dy * parent.wheelMultiplier));
|
|
||||||
ev.accepted = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: detailsRect
|
id: detailsRect
|
||||||
|
|||||||
@@ -114,9 +114,16 @@ Rectangle {
|
|||||||
opacity: hasEvents ? 1 : 0
|
opacity: hasEvents ? 1 : 0
|
||||||
clip: true
|
clip: true
|
||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
boundsMovement: Flickable.StopAtBounds
|
|
||||||
boundsBehavior: Flickable.StopAtBounds
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
|
|
||||||
|
// Enhanced native kinetic scrolling - faster for both touchpad and mouse
|
||||||
|
interactive: true
|
||||||
|
flickDeceleration: 1000 // Lower = more momentum, longer scrolling
|
||||||
|
maximumFlickVelocity: 8000 // Higher = faster maximum scroll speed
|
||||||
|
boundsMovement: Flickable.FollowBoundsBehavior
|
||||||
|
pressDelay: 0
|
||||||
|
flickableDirection: Flickable.VerticalFlick
|
||||||
|
|
||||||
ScrollBar.vertical: ScrollBar {
|
ScrollBar.vertical: ScrollBar {
|
||||||
policy: eventsList.contentHeight > eventsList.height ? ScrollBar.AsNeeded : ScrollBar.AlwaysOff
|
policy: eventsList.contentHeight > eventsList.height ? ScrollBar.AsNeeded : ScrollBar.AlwaysOff
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,8 +114,9 @@ Column {
|
|||||||
contentWidth: width
|
contentWidth: width
|
||||||
contentHeight: spanningNetworksColumn.height
|
contentHeight: spanningNetworksColumn.height
|
||||||
boundsBehavior: Flickable.DragAndOvershootBounds
|
boundsBehavior: Flickable.DragAndOvershootBounds
|
||||||
flickDeceleration: 8000
|
// Enhanced native kinetic scrolling - Qt handles touch vs mouse automatically
|
||||||
maximumFlickVelocity: 15000
|
flickDeceleration: 1000 // Lower = more momentum, longer scrolling
|
||||||
|
maximumFlickVelocity: 8000 // Higher = faster maximum scroll speed
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: spanningNetworksColumn
|
id: spanningNetworksColumn
|
||||||
|
|||||||
@@ -84,8 +84,9 @@ Item {
|
|||||||
contentWidth: width
|
contentWidth: width
|
||||||
contentHeight: wifiContent.height
|
contentHeight: wifiContent.height
|
||||||
boundsBehavior: Flickable.DragAndOvershootBounds
|
boundsBehavior: Flickable.DragAndOvershootBounds
|
||||||
flickDeceleration: 8000
|
// Enhanced native kinetic scrolling - faster for both touchpad and mouse
|
||||||
maximumFlickVelocity: 15000
|
flickDeceleration: 1000 // Lower = more momentum, longer scrolling
|
||||||
|
maximumFlickVelocity: 8000 // Higher = faster maximum scroll speed
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: wifiContent
|
id: wifiContent
|
||||||
@@ -115,8 +116,9 @@ Item {
|
|||||||
contentWidth: width
|
contentWidth: width
|
||||||
contentHeight: ethernetContent.height
|
contentHeight: ethernetContent.height
|
||||||
boundsBehavior: Flickable.StopAtBounds
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
flickDeceleration: 8000
|
// Enhanced native kinetic scrolling - faster for both touchpad and mouse
|
||||||
maximumFlickVelocity: 15000
|
flickDeceleration: 1000 // Lower = more momentum, longer scrolling
|
||||||
|
maximumFlickVelocity: 8000 // Higher = faster maximum scroll speed
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: ethernetContent
|
id: ethernetContent
|
||||||
|
|||||||
@@ -19,8 +19,13 @@ ListView {
|
|||||||
spacing: Theme.spacingL
|
spacing: Theme.spacingL
|
||||||
interactive: true
|
interactive: true
|
||||||
boundsBehavior: Flickable.StopAtBounds
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
flickDeceleration: 1500
|
|
||||||
maximumFlickVelocity: 2000
|
// Enhanced native kinetic scrolling - Qt handles touch vs mouse automatically
|
||||||
|
flickDeceleration: 1000 // Lower = more momentum, longer scrolling
|
||||||
|
maximumFlickVelocity: 8000 // Higher = faster maximum scroll speed
|
||||||
|
boundsMovement: Flickable.FollowBoundsBehavior
|
||||||
|
pressDelay: 0
|
||||||
|
flickableDirection: Flickable.VerticalFlick
|
||||||
cacheBuffer: 1000
|
cacheBuffer: 1000
|
||||||
onMovementStarted: isUserScrolling = true
|
onMovementStarted: isUserScrolling = true
|
||||||
onMovementEnded: {
|
onMovementEnded: {
|
||||||
|
|||||||
@@ -234,8 +234,6 @@ Column {
|
|||||||
property real stableY: 0
|
property real stableY: 0
|
||||||
property bool isUserScrolling: false
|
property bool isUserScrolling: false
|
||||||
property bool isScrollBarDragging: false
|
property bool isScrollBarDragging: false
|
||||||
property real wheelMultiplier: 1.8
|
|
||||||
property int wheelBaseStep: 160
|
|
||||||
property string keyRoleName: "pid"
|
property string keyRoleName: "pid"
|
||||||
property var _anchorKey: undefined
|
property var _anchorKey: undefined
|
||||||
property real _anchorOffset: 0
|
property real _anchorOffset: 0
|
||||||
@@ -278,39 +276,30 @@ Column {
|
|||||||
spacing: 4
|
spacing: 4
|
||||||
model: SysMonitorService.processes
|
model: SysMonitorService.processes
|
||||||
boundsBehavior: Flickable.StopAtBounds
|
boundsBehavior: Flickable.StopAtBounds
|
||||||
flickDeceleration: 1500
|
|
||||||
maximumFlickVelocity: 2000
|
// Enhanced native kinetic scrolling - faster for both touchpad and mouse
|
||||||
|
interactive: true
|
||||||
|
flickDeceleration: 1000 // Lower = more momentum, longer scrolling
|
||||||
|
maximumFlickVelocity: 8000 // Higher = faster maximum scroll speed
|
||||||
|
boundsMovement: Flickable.FollowBoundsBehavior
|
||||||
|
pressDelay: 0
|
||||||
|
flickableDirection: Flickable.VerticalFlick
|
||||||
|
|
||||||
onMovementStarted: isUserScrolling = true
|
onMovementStarted: isUserScrolling = true
|
||||||
onMovementEnded: {
|
onMovementEnded: {
|
||||||
isUserScrolling = false;
|
isUserScrolling = false;
|
||||||
if (contentY > 40)
|
if (contentY > 40)
|
||||||
stableY = contentY;
|
stableY = contentY;
|
||||||
|
|
||||||
}
|
}
|
||||||
onContentYChanged: {
|
onContentYChanged: {
|
||||||
if (!isUserScrolling && !isScrollBarDragging && visible && stableY > 40 && Math.abs(contentY - stableY) > 10)
|
if (!isUserScrolling && !isScrollBarDragging && visible && stableY > 40 && Math.abs(contentY - stableY) > 10)
|
||||||
contentY = stableY;
|
contentY = stableY;
|
||||||
|
|
||||||
}
|
}
|
||||||
onModelChanged: {
|
onModelChanged: {
|
||||||
if (model && model.length > 0 && !isUserScrolling && stableY > 40)
|
if (model && model.length > 0 && !isUserScrolling && stableY > 40)
|
||||||
Qt.callLater(function() {
|
Qt.callLater(function() {
|
||||||
contentY = stableY;
|
contentY = stableY;
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
WheelHandler {
|
|
||||||
target: null
|
|
||||||
onWheel: (ev) => {
|
|
||||||
let dy = ev.pixelDelta.y !== 0 ? ev.pixelDelta.y : (ev.angleDelta.y / 120) * processListView.wheelBaseStep;
|
|
||||||
if (ev.inverted)
|
|
||||||
dy = -dy;
|
|
||||||
|
|
||||||
const maxY = Math.max(0, processListView.contentHeight - processListView.height);
|
|
||||||
processListView.contentY = Math.max(0, Math.min(maxY, processListView.contentY - dy * processListView.wheelMultiplier));
|
|
||||||
ev.accepted = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate: ProcessListItem {
|
delegate: ProcessListItem {
|
||||||
|
|||||||
@@ -272,27 +272,20 @@ Rectangle {
|
|||||||
ListView {
|
ListView {
|
||||||
id: listView
|
id: listView
|
||||||
|
|
||||||
property real wheelMultiplier: 1.8
|
|
||||||
property int wheelBaseStep: 160
|
|
||||||
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: parent.height - (root.enableFuzzySearch ? searchContainer.height + Theme.spacingXS : 0)
|
height: parent.height - (root.enableFuzzySearch ? searchContainer.height + Theme.spacingXS : 0)
|
||||||
clip: true
|
clip: true
|
||||||
model: filteredOptions
|
model: filteredOptions
|
||||||
spacing: 2
|
spacing: 2
|
||||||
|
|
||||||
WheelHandler {
|
// Enhanced native kinetic scrolling - faster for both touchpad and mouse
|
||||||
target: null
|
interactive: true
|
||||||
onWheel: (ev) => {
|
flickDeceleration: 1000 // Lower = more momentum, longer scrolling
|
||||||
let dy = ev.pixelDelta.y !== 0 ? ev.pixelDelta.y : (ev.angleDelta.y / 120) * parent.wheelBaseStep;
|
maximumFlickVelocity: 8000 // Higher = faster maximum scroll speed
|
||||||
if (ev.inverted)
|
boundsBehavior: Flickable.DragAndOvershootBounds
|
||||||
dy = -dy;
|
boundsMovement: Flickable.FollowBoundsBehavior
|
||||||
|
pressDelay: 0
|
||||||
const maxY = Math.max(0, parent.contentHeight - parent.height);
|
flickableDirection: Flickable.VerticalFlick
|
||||||
parent.contentY = Math.max(0, Math.min(maxY, parent.contentY - dy * parent.wheelMultiplier));
|
|
||||||
ev.accepted = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ScrollBar.vertical: ScrollBar {
|
ScrollBar.vertical: ScrollBar {
|
||||||
policy: ScrollBar.AsNeeded
|
policy: ScrollBar.AsNeeded
|
||||||
|
|||||||
@@ -18,8 +18,6 @@ GridView {
|
|||||||
property int minIconSize: 32
|
property int minIconSize: 32
|
||||||
property bool hoverUpdatesSelection: true
|
property bool hoverUpdatesSelection: true
|
||||||
property bool keyboardNavigationActive: false
|
property bool keyboardNavigationActive: false
|
||||||
property real wheelMultiplier: 1.8
|
|
||||||
property int wheelBaseStep: 160
|
|
||||||
property int baseCellWidth: adaptiveColumns ? Math.max(minCellWidth, Math.min(maxCellWidth, width / columns)) : (width - Theme.spacingS * 2) / columns
|
property int baseCellWidth: adaptiveColumns ? Math.max(minCellWidth, Math.min(maxCellWidth, width / columns)) : (width - Theme.spacingS * 2) / columns
|
||||||
property int baseCellHeight: baseCellWidth + 20
|
property int baseCellHeight: baseCellWidth + 20
|
||||||
property int actualColumns: adaptiveColumns ? Math.floor(width / cellWidth) : columns
|
property int actualColumns: adaptiveColumns ? Math.floor(width / cellWidth) : columns
|
||||||
@@ -55,21 +53,14 @@ GridView {
|
|||||||
rightMargin: leftMargin
|
rightMargin: leftMargin
|
||||||
focus: true
|
focus: true
|
||||||
interactive: true
|
interactive: true
|
||||||
flickDeceleration: 300
|
|
||||||
maximumFlickVelocity: 30000
|
// Enhanced native kinetic scrolling - faster for both touchpad and mouse
|
||||||
|
flickDeceleration: 1000 // Lower = more momentum, longer scrolling
|
||||||
WheelHandler {
|
maximumFlickVelocity: 8000 // Higher = faster maximum scroll speed
|
||||||
target: null
|
boundsBehavior: Flickable.DragAndOvershootBounds
|
||||||
onWheel: (ev) => {
|
boundsMovement: Flickable.FollowBoundsBehavior
|
||||||
let dy = ev.pixelDelta.y !== 0 ? ev.pixelDelta.y : (ev.angleDelta.y / 120) * gridView.wheelBaseStep;
|
pressDelay: 0
|
||||||
if (ev.inverted)
|
flickableDirection: Flickable.VerticalFlick
|
||||||
dy = -dy;
|
|
||||||
|
|
||||||
const maxY = Math.max(0, gridView.contentHeight - gridView.height);
|
|
||||||
gridView.contentY = Math.max(0, Math.min(maxY, gridView.contentY - dy * gridView.wheelMultiplier));
|
|
||||||
ev.accepted = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ScrollBar.vertical: ScrollBar {
|
ScrollBar.vertical: ScrollBar {
|
||||||
policy: ScrollBar.AsNeeded
|
policy: ScrollBar.AsNeeded
|
||||||
|
|||||||
@@ -13,8 +13,6 @@ ListView {
|
|||||||
property int itemSpacing: Theme.spacingS
|
property int itemSpacing: Theme.spacingS
|
||||||
property bool hoverUpdatesSelection: true
|
property bool hoverUpdatesSelection: true
|
||||||
property bool keyboardNavigationActive: false
|
property bool keyboardNavigationActive: false
|
||||||
property real wheelMultiplier: 1.8
|
|
||||||
property int wheelBaseStep: 160
|
|
||||||
|
|
||||||
signal keyboardNavigationReset()
|
signal keyboardNavigationReset()
|
||||||
signal itemClicked(int index, var modelData)
|
signal itemClicked(int index, var modelData)
|
||||||
@@ -36,28 +34,21 @@ ListView {
|
|||||||
onCurrentIndexChanged: {
|
onCurrentIndexChanged: {
|
||||||
if (keyboardNavigationActive)
|
if (keyboardNavigationActive)
|
||||||
ensureVisible(currentIndex);
|
ensureVisible(currentIndex);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
clip: true
|
clip: true
|
||||||
anchors.margins: itemSpacing
|
anchors.margins: itemSpacing
|
||||||
spacing: itemSpacing
|
spacing: itemSpacing
|
||||||
focus: true
|
focus: true
|
||||||
interactive: true
|
interactive: true
|
||||||
flickDeceleration: 600
|
|
||||||
maximumFlickVelocity: 30000
|
// Enhanced native kinetic scrolling - faster for both touchpad and mouse
|
||||||
|
flickDeceleration: 1000 // Lower = more momentum, longer scrolling
|
||||||
WheelHandler {
|
maximumFlickVelocity: 8000 // Higher = faster maximum scroll speed
|
||||||
target: null
|
boundsBehavior: Flickable.DragAndOvershootBounds
|
||||||
onWheel: (ev) => {
|
boundsMovement: Flickable.FollowBoundsBehavior
|
||||||
let dy = ev.pixelDelta.y !== 0 ? ev.pixelDelta.y : (ev.angleDelta.y / 120) * wheelBaseStep;
|
pressDelay: 0
|
||||||
if (ev.inverted)
|
flickableDirection: Flickable.VerticalFlick
|
||||||
dy = -dy;
|
|
||||||
|
|
||||||
const maxY = Math.max(0, contentHeight - height);
|
|
||||||
contentY = Math.max(0, Math.min(maxY, contentY - dy * wheelMultiplier));
|
|
||||||
ev.accepted = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ScrollBar.vertical: ScrollBar {
|
ScrollBar.vertical: ScrollBar {
|
||||||
policy: ScrollBar.AlwaysOn
|
policy: ScrollBar.AlwaysOn
|
||||||
|
|||||||
@@ -258,6 +258,15 @@ Item {
|
|||||||
model: searchResultsModel
|
model: searchResultsModel
|
||||||
spacing: 2
|
spacing: 2
|
||||||
|
|
||||||
|
// Enhanced native kinetic scrolling - faster for both touchpad and mouse
|
||||||
|
interactive: true
|
||||||
|
flickDeceleration: 1000 // Lower = more momentum, longer scrolling
|
||||||
|
maximumFlickVelocity: 8000 // Higher = faster maximum scroll speed
|
||||||
|
boundsBehavior: Flickable.DragAndOvershootBounds
|
||||||
|
boundsMovement: Flickable.FollowBoundsBehavior
|
||||||
|
pressDelay: 0
|
||||||
|
flickableDirection: Flickable.VerticalFlick
|
||||||
|
|
||||||
delegate: StyledRect {
|
delegate: StyledRect {
|
||||||
width: searchResultsList.width
|
width: searchResultsList.width
|
||||||
height: 36
|
height: 36
|
||||||
|
|||||||
@@ -102,6 +102,15 @@ Popup {
|
|||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
model: root.allWidgets
|
model: root.allWidgets
|
||||||
|
|
||||||
|
// Enhanced native kinetic scrolling - faster for both touchpad and mouse
|
||||||
|
interactive: true
|
||||||
|
flickDeceleration: 1000 // Lower = more momentum, longer scrolling
|
||||||
|
maximumFlickVelocity: 8000 // Higher = faster maximum scroll speed
|
||||||
|
boundsBehavior: Flickable.DragAndOvershootBounds
|
||||||
|
boundsMovement: Flickable.FollowBoundsBehavior
|
||||||
|
pressDelay: 0
|
||||||
|
flickableDirection: Flickable.VerticalFlick
|
||||||
|
|
||||||
delegate: Rectangle {
|
delegate: Rectangle {
|
||||||
width: widgetList.width
|
width: widgetList.width
|
||||||
height: 60
|
height: 60
|
||||||
|
|||||||
Reference in New Issue
Block a user