mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-07 14:05:38 -05:00
Implement light & dark mode theme options
This commit is contained in:
@@ -8,6 +8,7 @@ Singleton {
|
||||
|
||||
property int themeIndex: 0
|
||||
property bool themeIsDynamic: false
|
||||
property bool isLightMode: false
|
||||
property var recentlyUsedApps: []
|
||||
|
||||
readonly property string configDir: Qt.resolvedUrl("file://" + Quickshell.env("HOME") + "/.config/DankMaterialDark")
|
||||
@@ -57,8 +58,9 @@ Singleton {
|
||||
var settings = JSON.parse(content)
|
||||
themeIndex = settings.themeIndex !== undefined ? settings.themeIndex : 0
|
||||
themeIsDynamic = settings.themeIsDynamic !== undefined ? settings.themeIsDynamic : false
|
||||
isLightMode = settings.isLightMode !== undefined ? settings.isLightMode : false
|
||||
recentlyUsedApps = settings.recentlyUsedApps || []
|
||||
console.log("Loaded settings - themeIndex:", themeIndex, "isDynamic:", themeIsDynamic, "recentApps:", recentlyUsedApps.length)
|
||||
console.log("Loaded settings - themeIndex:", themeIndex, "isDynamic:", themeIsDynamic, "lightMode:", isLightMode, "recentApps:", recentlyUsedApps.length)
|
||||
} else {
|
||||
console.log("Settings file is empty")
|
||||
}
|
||||
@@ -81,6 +83,7 @@ Singleton {
|
||||
var settings = {
|
||||
themeIndex: themeIndex,
|
||||
themeIsDynamic: themeIsDynamic,
|
||||
isLightMode: isLightMode,
|
||||
recentlyUsedApps: recentlyUsedApps
|
||||
}
|
||||
|
||||
@@ -88,7 +91,7 @@ Singleton {
|
||||
|
||||
writeProcess.command = ["sh", "-c", "echo '" + content + "' > '" + Quickshell.env("HOME") + "/.config/DankMaterialDark/settings.json'"]
|
||||
writeProcess.running = true
|
||||
console.log("Saving settings - themeIndex:", themeIndex, "isDynamic:", themeIsDynamic, "recentApps:", recentlyUsedApps.length)
|
||||
console.log("Saving settings - themeIndex:", themeIndex, "isDynamic:", themeIsDynamic, "lightMode:", isLightMode, "recentApps:", recentlyUsedApps.length)
|
||||
}
|
||||
|
||||
function applyStoredTheme() {
|
||||
@@ -112,6 +115,12 @@ Singleton {
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setLightMode(lightMode) {
|
||||
console.log("Prefs setLightMode called - isLightMode:", lightMode)
|
||||
isLightMode = lightMode
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function addRecentApp(app) {
|
||||
var existingIndex = -1
|
||||
for (var i = 0; i < recentlyUsedApps.length; i++) {
|
||||
|
||||
229
Common/Theme.qml
229
Common/Theme.qml
@@ -21,7 +21,8 @@ QtObject {
|
||||
|
||||
Qt.callLater(() => {
|
||||
if (typeof Prefs !== "undefined") {
|
||||
console.log("Theme applying saved preferences:", Prefs.themeIndex, Prefs.themeIsDynamic)
|
||||
console.log("Theme applying saved preferences:", Prefs.themeIndex, Prefs.themeIsDynamic, "lightMode:", Prefs.isLightMode)
|
||||
isLightMode = Prefs.isLightMode
|
||||
switchTheme(Prefs.themeIndex, Prefs.themeIsDynamic, false) // Don't save during startup
|
||||
}
|
||||
})
|
||||
@@ -220,9 +221,184 @@ QtObject {
|
||||
}
|
||||
]
|
||||
|
||||
// Light theme variants
|
||||
property var lightThemes: [
|
||||
{
|
||||
name: "Blue Light",
|
||||
primary: "#1976d2",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#e3f2fd",
|
||||
secondary: "#42a5f5",
|
||||
surface: "#fefefe",
|
||||
surfaceText: "#1a1c1e",
|
||||
surfaceVariant: "#e7e0ec",
|
||||
surfaceVariantText: "#49454f",
|
||||
surfaceTint: "#1976d2",
|
||||
background: "#fefefe",
|
||||
backgroundText: "#1a1c1e",
|
||||
outline: "#79747e",
|
||||
surfaceContainer: "#f3f3f3",
|
||||
surfaceContainerHigh: "#ececec"
|
||||
},
|
||||
{
|
||||
name: "Deep Blue Light",
|
||||
primary: "#0061a4",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#cfe5ff",
|
||||
secondary: "#1976d2",
|
||||
surface: "#fefefe",
|
||||
surfaceText: "#1a1c1e",
|
||||
surfaceVariant: "#e7e0ec",
|
||||
surfaceVariantText: "#49454f",
|
||||
surfaceTint: "#0061a4",
|
||||
background: "#fefefe",
|
||||
backgroundText: "#1a1c1e",
|
||||
outline: "#79747e",
|
||||
surfaceContainer: "#f3f3f3",
|
||||
surfaceContainerHigh: "#ececec"
|
||||
},
|
||||
{
|
||||
name: "Purple Light",
|
||||
primary: "#6750A4",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#EADDFF",
|
||||
secondary: "#625B71",
|
||||
surface: "#FFFBFE",
|
||||
surfaceText: "#1C1B1F",
|
||||
surfaceVariant: "#E7E0EC",
|
||||
surfaceVariantText: "#49454F",
|
||||
surfaceTint: "#6750A4",
|
||||
background: "#FFFBFE",
|
||||
backgroundText: "#1C1B1F",
|
||||
outline: "#79747E",
|
||||
surfaceContainer: "#F3EDF7",
|
||||
surfaceContainerHigh: "#ECE6F0"
|
||||
},
|
||||
{
|
||||
name: "Green Light",
|
||||
primary: "#2e7d32",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#e8f5e8",
|
||||
secondary: "#4caf50",
|
||||
surface: "#fefefe",
|
||||
surfaceText: "#1a1c1e",
|
||||
surfaceVariant: "#e7e0ec",
|
||||
surfaceVariantText: "#49454f",
|
||||
surfaceTint: "#2e7d32",
|
||||
background: "#fefefe",
|
||||
backgroundText: "#1a1c1e",
|
||||
outline: "#79747e",
|
||||
surfaceContainer: "#f3f3f3",
|
||||
surfaceContainerHigh: "#ececec"
|
||||
},
|
||||
{
|
||||
name: "Orange Light",
|
||||
primary: "#e65100",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#ffecb3",
|
||||
secondary: "#ff9800",
|
||||
surface: "#fefefe",
|
||||
surfaceText: "#1a1c1e",
|
||||
surfaceVariant: "#e7e0ec",
|
||||
surfaceVariantText: "#49454f",
|
||||
surfaceTint: "#e65100",
|
||||
background: "#fefefe",
|
||||
backgroundText: "#1a1c1e",
|
||||
outline: "#79747e",
|
||||
surfaceContainer: "#f3f3f3",
|
||||
surfaceContainerHigh: "#ececec"
|
||||
},
|
||||
{
|
||||
name: "Red Light",
|
||||
primary: "#d32f2f",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#ffebee",
|
||||
secondary: "#f44336",
|
||||
surface: "#fefefe",
|
||||
surfaceText: "#1a1c1e",
|
||||
surfaceVariant: "#e7e0ec",
|
||||
surfaceVariantText: "#49454f",
|
||||
surfaceTint: "#d32f2f",
|
||||
background: "#fefefe",
|
||||
backgroundText: "#1a1c1e",
|
||||
outline: "#79747e",
|
||||
surfaceContainer: "#f3f3f3",
|
||||
surfaceContainerHigh: "#ececec"
|
||||
},
|
||||
{
|
||||
name: "Cyan Light",
|
||||
primary: "#0097a7",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#e0f2f1",
|
||||
secondary: "#00bcd4",
|
||||
surface: "#fefefe",
|
||||
surfaceText: "#1a1c1e",
|
||||
surfaceVariant: "#e7e0ec",
|
||||
surfaceVariantText: "#49454f",
|
||||
surfaceTint: "#0097a7",
|
||||
background: "#fefefe",
|
||||
backgroundText: "#1a1c1e",
|
||||
outline: "#79747e",
|
||||
surfaceContainer: "#f3f3f3",
|
||||
surfaceContainerHigh: "#ececec"
|
||||
},
|
||||
{
|
||||
name: "Pink Light",
|
||||
primary: "#c2185b",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#fce4ec",
|
||||
secondary: "#e91e63",
|
||||
surface: "#fefefe",
|
||||
surfaceText: "#1a1c1e",
|
||||
surfaceVariant: "#e7e0ec",
|
||||
surfaceVariantText: "#49454f",
|
||||
surfaceTint: "#c2185b",
|
||||
background: "#fefefe",
|
||||
backgroundText: "#1a1c1e",
|
||||
outline: "#79747e",
|
||||
surfaceContainer: "#f3f3f3",
|
||||
surfaceContainerHigh: "#ececec"
|
||||
},
|
||||
{
|
||||
name: "Amber Light",
|
||||
primary: "#ff8f00",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#fff8e1",
|
||||
secondary: "#ffc107",
|
||||
surface: "#fefefe",
|
||||
surfaceText: "#1a1c1e",
|
||||
surfaceVariant: "#e7e0ec",
|
||||
surfaceVariantText: "#49454f",
|
||||
surfaceTint: "#ff8f00",
|
||||
background: "#fefefe",
|
||||
backgroundText: "#1a1c1e",
|
||||
outline: "#79747e",
|
||||
surfaceContainer: "#f3f3f3",
|
||||
surfaceContainerHigh: "#ececec"
|
||||
},
|
||||
{
|
||||
name: "Coral Light",
|
||||
primary: "#8c1d18",
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#ffdad6",
|
||||
secondary: "#ff5449",
|
||||
surface: "#fefefe",
|
||||
surfaceText: "#1a1c1e",
|
||||
surfaceVariant: "#e7e0ec",
|
||||
surfaceVariantText: "#49454f",
|
||||
surfaceTint: "#8c1d18",
|
||||
background: "#fefefe",
|
||||
backgroundText: "#1a1c1e",
|
||||
outline: "#79747e",
|
||||
surfaceContainer: "#f3f3f3",
|
||||
surfaceContainerHigh: "#ececec"
|
||||
}
|
||||
]
|
||||
|
||||
// Current theme index (10 = Auto/Dynamic)
|
||||
property int currentThemeIndex: 0
|
||||
property bool isDynamicTheme: false
|
||||
property bool isLightMode: false
|
||||
|
||||
// Function to switch themes
|
||||
function switchTheme(themeIndex, isDynamic = false, savePrefs = true) {
|
||||
@@ -252,21 +428,44 @@ QtObject {
|
||||
}
|
||||
}
|
||||
|
||||
// Function to toggle light/dark mode
|
||||
function toggleLightMode(savePrefs = true) {
|
||||
console.log("Theme.toggleLightMode called, current isLightMode:", isLightMode)
|
||||
isLightMode = !isLightMode
|
||||
console.log("Light mode toggled to:", isLightMode)
|
||||
|
||||
// Save preference
|
||||
if (savePrefs && typeof Prefs !== "undefined") {
|
||||
Prefs.setLightMode(isLightMode)
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to get current theme array
|
||||
function getCurrentThemeArray() {
|
||||
return isLightMode ? lightThemes : themes
|
||||
}
|
||||
|
||||
// Helper function to get current theme
|
||||
function getCurrentTheme() {
|
||||
var themeArray = getCurrentThemeArray()
|
||||
return currentThemeIndex < themeArray.length ? themeArray[currentThemeIndex] : themeArray[0]
|
||||
}
|
||||
|
||||
// Dynamic color properties that change based on current theme
|
||||
property color primary: isDynamicTheme ? Colors.accentHi : (currentThemeIndex < themes.length ? themes[currentThemeIndex].primary : themes[0].primary)
|
||||
property color primaryText: isDynamicTheme ? Colors.primaryText : (currentThemeIndex < themes.length ? themes[currentThemeIndex].primaryText : themes[0].primaryText)
|
||||
property color primaryContainer: isDynamicTheme ? Colors.primaryContainer : (currentThemeIndex < themes.length ? themes[currentThemeIndex].primaryContainer : themes[0].primaryContainer)
|
||||
property color secondary: isDynamicTheme ? Colors.accentLo : (currentThemeIndex < themes.length ? themes[currentThemeIndex].secondary : themes[0].secondary)
|
||||
property color surface: isDynamicTheme ? Colors.surface : (currentThemeIndex < themes.length ? themes[currentThemeIndex].surface : themes[0].surface)
|
||||
property color surfaceText: isDynamicTheme ? Colors.surfaceText : (currentThemeIndex < themes.length ? themes[currentThemeIndex].surfaceText : themes[0].surfaceText)
|
||||
property color surfaceVariant: isDynamicTheme ? Colors.surfaceVariant : (currentThemeIndex < themes.length ? themes[currentThemeIndex].surfaceVariant : themes[0].surfaceVariant)
|
||||
property color surfaceVariantText: isDynamicTheme ? Colors.surfaceVariantText : (currentThemeIndex < themes.length ? themes[currentThemeIndex].surfaceVariantText : themes[0].surfaceVariantText)
|
||||
property color surfaceTint: isDynamicTheme ? Colors.surfaceTint : (currentThemeIndex < themes.length ? themes[currentThemeIndex].surfaceTint : themes[0].surfaceTint)
|
||||
property color background: isDynamicTheme ? Colors.background : (currentThemeIndex < themes.length ? themes[currentThemeIndex].background : themes[0].background)
|
||||
property color backgroundText: isDynamicTheme ? Colors.backgroundText : (currentThemeIndex < themes.length ? themes[currentThemeIndex].backgroundText : themes[0].backgroundText)
|
||||
property color outline: isDynamicTheme ? Colors.outline : (currentThemeIndex < themes.length ? themes[currentThemeIndex].outline : themes[0].outline)
|
||||
property color surfaceContainer: isDynamicTheme ? Colors.surfaceContainer : (currentThemeIndex < themes.length ? themes[currentThemeIndex].surfaceContainer : themes[0].surfaceContainer)
|
||||
property color surfaceContainerHigh: isDynamicTheme ? Colors.surfaceContainerHigh : (currentThemeIndex < themes.length ? themes[currentThemeIndex].surfaceContainerHigh : themes[0].surfaceContainerHigh)
|
||||
property color primary: isDynamicTheme ? Colors.accentHi : getCurrentTheme().primary
|
||||
property color primaryText: isDynamicTheme ? Colors.primaryText : getCurrentTheme().primaryText
|
||||
property color primaryContainer: isDynamicTheme ? Colors.primaryContainer : getCurrentTheme().primaryContainer
|
||||
property color secondary: isDynamicTheme ? Colors.accentLo : getCurrentTheme().secondary
|
||||
property color surface: isDynamicTheme ? Colors.surface : getCurrentTheme().surface
|
||||
property color surfaceText: isDynamicTheme ? Colors.surfaceText : getCurrentTheme().surfaceText
|
||||
property color surfaceVariant: isDynamicTheme ? Colors.surfaceVariant : getCurrentTheme().surfaceVariant
|
||||
property color surfaceVariantText: isDynamicTheme ? Colors.surfaceVariantText : getCurrentTheme().surfaceVariantText
|
||||
property color surfaceTint: isDynamicTheme ? Colors.surfaceTint : getCurrentTheme().surfaceTint
|
||||
property color background: isDynamicTheme ? Colors.background : getCurrentTheme().background
|
||||
property color backgroundText: isDynamicTheme ? Colors.backgroundText : getCurrentTheme().backgroundText
|
||||
property color outline: isDynamicTheme ? Colors.outline : getCurrentTheme().outline
|
||||
property color surfaceContainer: isDynamicTheme ? Colors.surfaceContainer : getCurrentTheme().surfaceContainer
|
||||
property color surfaceContainerHigh: isDynamicTheme ? Colors.surfaceContainerHigh : getCurrentTheme().surfaceContainerHigh
|
||||
|
||||
// Static colors that don't change with themes
|
||||
property color archBlue: "#1793D1"
|
||||
|
||||
@@ -56,55 +56,110 @@ ScrollView {
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
// Night mode toggle
|
||||
Rectangle {
|
||||
// Mode toggles row (Night Mode + Light/Dark Mode)
|
||||
Row {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: displayTab.nightModeEnabled ?
|
||||
Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) :
|
||||
(nightModeToggle.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08))
|
||||
border.color: displayTab.nightModeEnabled ? Theme.primary : "transparent"
|
||||
border.width: displayTab.nightModeEnabled ? 1 : 0
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
// Night mode toggle
|
||||
Rectangle {
|
||||
width: (parent.width - Theme.spacingM) / 2
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: displayTab.nightModeEnabled ?
|
||||
Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) :
|
||||
(nightModeToggle.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08))
|
||||
border.color: displayTab.nightModeEnabled ? Theme.primary : "transparent"
|
||||
border.width: displayTab.nightModeEnabled ? 1 : 0
|
||||
|
||||
Text {
|
||||
text: displayTab.nightModeEnabled ? "nightlight" : "dark_mode"
|
||||
font.family: Theme.iconFont
|
||||
font.pixelSize: Theme.iconSize
|
||||
color: displayTab.nightModeEnabled ? Theme.primary : Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
Text {
|
||||
text: displayTab.nightModeEnabled ? "nightlight" : "dark_mode"
|
||||
font.family: Theme.iconFont
|
||||
font.pixelSize: Theme.iconSize
|
||||
color: displayTab.nightModeEnabled ? Theme.primary : Theme.surfaceText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Night Mode"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: displayTab.nightModeEnabled ? Theme.primary : Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Night Mode" + (displayTab.nightModeEnabled ? " (On)" : "")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: displayTab.nightModeEnabled ? Theme.primary : Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
MouseArea {
|
||||
id: nightModeToggle
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
onClicked: {
|
||||
if (displayTab.nightModeEnabled) {
|
||||
// Disable night mode - kill any running color temperature processes
|
||||
nightModeDisableProcess.running = true
|
||||
displayTab.nightModeEnabled = false
|
||||
} else {
|
||||
// Enable night mode using wlsunset or redshift
|
||||
nightModeEnableProcess.running = true
|
||||
displayTab.nightModeEnabled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: nightModeToggle
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
// Light/Dark mode toggle
|
||||
Rectangle {
|
||||
width: (parent.width - Theme.spacingM) / 2
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.isLightMode ?
|
||||
Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) :
|
||||
(lightModeToggle.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08))
|
||||
border.color: Theme.isLightMode ? Theme.primary : "transparent"
|
||||
border.width: Theme.isLightMode ? 1 : 0
|
||||
|
||||
onClicked: {
|
||||
if (displayTab.nightModeEnabled) {
|
||||
// Disable night mode - kill any running color temperature processes
|
||||
nightModeDisableProcess.running = true
|
||||
displayTab.nightModeEnabled = false
|
||||
} else {
|
||||
// Enable night mode using wlsunset or redshift
|
||||
nightModeEnableProcess.running = true
|
||||
displayTab.nightModeEnabled = true
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
Text {
|
||||
text: Theme.isLightMode ? "light_mode" : "palette"
|
||||
font.family: Theme.iconFont
|
||||
font.pixelSize: Theme.iconSize
|
||||
color: Theme.isLightMode ? Theme.primary : Theme.surfaceText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
Text {
|
||||
text: Theme.isLightMode ? "Light Mode" : "Dark Mode"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.isLightMode ? Theme.primary : Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: lightModeToggle
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
onClicked: {
|
||||
Theme.toggleLightMode()
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,6 +184,12 @@ Column {
|
||||
}
|
||||
}
|
||||
|
||||
// Spacer for better visual separation
|
||||
Item {
|
||||
width: 1
|
||||
height: Theme.spacingM
|
||||
}
|
||||
|
||||
// Auto theme button - prominent oval below the grid
|
||||
Rectangle {
|
||||
width: 120
|
||||
|
||||
Reference in New Issue
Block a user