forked from Shinonome/dots-hyprland
wallpaper safety
This commit is contained in:
@@ -45,6 +45,10 @@ Variants {
|
||||
|| Config.options.background.wallpaperPath.endsWith(".avi")
|
||||
|| Config.options.background.wallpaperPath.endsWith(".mov")
|
||||
property string wallpaperPath: wallpaperIsVideo ? Config.options.background.thumbnailPath : Config.options.background.wallpaperPath
|
||||
property bool wallpaperSafetyTriggered: Config.options.background.wallpaperSafety.enable && (
|
||||
CF.StringUtils.stringListContainsSubstring(wallpaperPath.toLowerCase(), Config.options.background.wallpaperSafety.triggerCondition.wallpaperKeywords) &&
|
||||
CF.StringUtils.stringListContainsSubstring(Network.networkName.toLowerCase(), Config.options.background.wallpaperSafety.triggerCondition.networkNameKeywords)
|
||||
)
|
||||
property real wallpaperToScreenRatio: Math.min(wallpaperWidth / screen.width, wallpaperHeight / screen.height)
|
||||
property real preferredWallpaperScale: Config.options.background.parallax.workspaceZoom
|
||||
property real effectiveWallpaperScale: 1 // Some reasonable init value, to be updated
|
||||
@@ -57,7 +61,7 @@ Variants {
|
||||
property real clockX: (modelData.width / 2)
|
||||
property real clockY: (modelData.height / 2)
|
||||
property var textHorizontalAlignment: {
|
||||
if (Config.options.background.lockBlur.enable && Config.options.background.lockBlur.centerClock && GlobalStates.screenLocked)
|
||||
if ((Config.options.background.lockBlur.enable && Config.options.background.lockBlur.centerClock && GlobalStates.screenLocked) || wallpaperSafetyTriggered)
|
||||
return Text.AlignHCenter;
|
||||
if (clockX < screen.width / 3)
|
||||
return Text.AlignLeft;
|
||||
@@ -69,11 +73,61 @@ Variants {
|
||||
property bool shouldBlur: (GlobalStates.screenLocked && Config.options.background.lockBlur.enable)
|
||||
property color dominantColor: Appearance.colors.colPrimary
|
||||
property bool dominantColorIsDark: dominantColor.hslLightness < 0.5
|
||||
property color colText: (GlobalStates.screenLocked && shouldBlur) ? Appearance.colors.colOnLayer0 : CF.ColorUtils.colorWithLightness(Appearance.colors.colPrimary, (dominantColorIsDark ? 0.8 : 0.12))
|
||||
property color colText: {
|
||||
if (wallpaperSafetyTriggered) return CF.ColorUtils.mix(Appearance.colors.colOnLayer0, Appearance.colors.colPrimary, 0.75);
|
||||
return (GlobalStates.screenLocked && shouldBlur) ? Appearance.colors.colOnLayer0 : CF.ColorUtils.colorWithLightness(Appearance.colors.colPrimary, (dominantColorIsDark ? 0.8 : 0.12))
|
||||
}
|
||||
Behavior on colText {
|
||||
animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this)
|
||||
}
|
||||
|
||||
// Components
|
||||
component ClockText: StyledText {
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: bgRoot.textHorizontalAlignment
|
||||
font {
|
||||
family: Appearance.font.family.expressive
|
||||
pixelSize: 20
|
||||
weight: Font.DemiBold
|
||||
}
|
||||
color: bgRoot.colText
|
||||
style: Text.Raised
|
||||
styleColor: Appearance.colors.colShadow
|
||||
animateChange: true
|
||||
}
|
||||
component ClockStatusText: RowLayout {
|
||||
id: statusTextRow
|
||||
property alias statusIcon: statusIconWidget.text
|
||||
property alias statusText: statusTextWidget.text
|
||||
property bool shown: true
|
||||
opacity: shown ? 1 : 0
|
||||
visible: opacity > 0
|
||||
Behavior on opacity {
|
||||
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
||||
}
|
||||
Layout.fillWidth: false
|
||||
MaterialSymbol {
|
||||
id: statusIconWidget
|
||||
Layout.fillWidth: false
|
||||
iconSize: Appearance.font.pixelSize.huge
|
||||
color: bgRoot.colText
|
||||
style: Text.Raised
|
||||
styleColor: Appearance.colors.colShadow
|
||||
}
|
||||
ClockText {
|
||||
id: statusTextWidget
|
||||
Layout.fillWidth: false
|
||||
color: bgRoot.colText
|
||||
font {
|
||||
family: Appearance.font.family.main
|
||||
pixelSize: Appearance.font.pixelSize.large
|
||||
weight: Font.Normal
|
||||
}
|
||||
style: Text.Raised
|
||||
styleColor: Appearance.colors.colShadow
|
||||
}
|
||||
}
|
||||
|
||||
// Layer props
|
||||
screen: modelData
|
||||
exclusionMode: ExclusionMode.Ignore
|
||||
@@ -86,7 +140,10 @@ Variants {
|
||||
left: true
|
||||
right: true
|
||||
}
|
||||
color: "transparent"
|
||||
color: CF.ColorUtils.mix(Appearance.colors.colLayer0, Appearance.colors.colPrimary, 0.75);
|
||||
Behavior on color {
|
||||
animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this)
|
||||
}
|
||||
|
||||
onWallpaperPathChanged: {
|
||||
bgRoot.updateZoomScale()
|
||||
@@ -206,7 +263,12 @@ Variants {
|
||||
property real effectiveValueY: Math.max(0, Math.min(1, valueY))
|
||||
x: -(bgRoot.movableXSpace) - (effectiveValueX - 0.5) * 2 * bgRoot.movableXSpace
|
||||
y: -(bgRoot.movableYSpace) - (effectiveValueY - 0.5) * 2 * bgRoot.movableYSpace
|
||||
source: bgRoot.wallpaperPath
|
||||
source: {
|
||||
print("-----------------")
|
||||
print("Safety triggered:", bgRoot.wallpaperSafetyTriggered);
|
||||
print("Wallpaper path:", bgRoot.wallpaperPath);
|
||||
return bgRoot.wallpaperSafetyTriggered ? "" : bgRoot.wallpaperPath
|
||||
}
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
Behavior on x {
|
||||
NumberAnimation {
|
||||
@@ -278,13 +340,14 @@ Variants {
|
||||
}
|
||||
states: State {
|
||||
name: "centered"
|
||||
when: bgRoot.shouldBlur && Config.options.background.lockBlur.centerClock
|
||||
when: (bgRoot.shouldBlur && Config.options.background.lockBlur.centerClock) || bgRoot.wallpaperSafetyTriggered
|
||||
AnchorChanges {
|
||||
target: clockLoader
|
||||
anchors {
|
||||
left: undefined
|
||||
right: undefined
|
||||
top: parent.top
|
||||
top: undefined
|
||||
verticalCenter: parent.verticalCenter
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
}
|
||||
@@ -306,46 +369,27 @@ Variants {
|
||||
anchors.centerIn: parent
|
||||
spacing: 6
|
||||
|
||||
StyledText {
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: bgRoot.textHorizontalAlignment
|
||||
font {
|
||||
family: Appearance.font.family.expressive
|
||||
pixelSize: 90
|
||||
weight: Font.Bold
|
||||
}
|
||||
color: bgRoot.colText
|
||||
style: Text.Raised
|
||||
styleColor: Appearance.colors.colShadow
|
||||
ClockText {
|
||||
font.pixelSize: 90
|
||||
text: DateTime.time
|
||||
}
|
||||
StyledText {
|
||||
Layout.fillWidth: true
|
||||
ClockText {
|
||||
Layout.topMargin: -5
|
||||
horizontalAlignment: bgRoot.textHorizontalAlignment
|
||||
font {
|
||||
family: Appearance.font.family.expressive
|
||||
pixelSize: 20
|
||||
weight: Font.DemiBold
|
||||
}
|
||||
color: bgRoot.colText
|
||||
style: Text.Raised
|
||||
styleColor: Appearance.colors.colShadow
|
||||
text: DateTime.date
|
||||
animateChange: true
|
||||
}
|
||||
StyledText {
|
||||
StyledText { // Somehow gets fucked up if made a ClockText???
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: bgRoot.textHorizontalAlignment
|
||||
font {
|
||||
family: Appearance.font.family.expressive
|
||||
pixelSize: 20
|
||||
weight: Font.DemiBold
|
||||
family: Appearance.font.family.main
|
||||
pixelSize: Appearance.font.pixelSize.normal
|
||||
weight: 350
|
||||
italic: true
|
||||
}
|
||||
color: bgRoot.colText
|
||||
style: Text.Raised
|
||||
visible: Config.options.background.quote !== ""
|
||||
styleColor: Appearance.colors.colShadow
|
||||
// visible: Config.options.background.quote.length > 0
|
||||
text: Config.options.background.quote
|
||||
}
|
||||
}
|
||||
@@ -356,31 +400,21 @@ Variants {
|
||||
left: bgRoot.textHorizontalAlignment === Text.AlignLeft ? clockColumn.left : undefined
|
||||
right: bgRoot.textHorizontalAlignment === Text.AlignRight ? clockColumn.right : undefined
|
||||
horizontalCenter: bgRoot.textHorizontalAlignment === Text.AlignHCenter ? clockColumn.horizontalCenter : undefined
|
||||
topMargin: 5
|
||||
leftMargin: -5
|
||||
rightMargin: -5
|
||||
}
|
||||
opacity: GlobalStates.screenLocked && (!Config.options.background.lockBlur.enable || Config.options.background.lockBlur.showLockedText) ? 1 : 0
|
||||
visible: opacity > 0
|
||||
Behavior on opacity {
|
||||
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
|
||||
topMargin: 14
|
||||
leftMargin: -6
|
||||
rightMargin: -6
|
||||
}
|
||||
spacing: 16
|
||||
Item { Layout.fillWidth: bgRoot.textHorizontalAlignment !== Text.AlignLeft; implicitWidth: 1 }
|
||||
MaterialSymbol {
|
||||
text: "lock"
|
||||
Layout.fillWidth: false
|
||||
iconSize: Appearance.font.pixelSize.huge
|
||||
color: bgRoot.colText
|
||||
style: Text.Raised
|
||||
styleColor: Appearance.colors.colShadow
|
||||
ClockStatusText {
|
||||
shown: bgRoot.wallpaperSafetyTriggered
|
||||
statusIcon: "hide_image"
|
||||
statusText: qsTr("Wallpaper safety enforced")
|
||||
}
|
||||
StyledText {
|
||||
Layout.fillWidth: false
|
||||
text: "Locked"
|
||||
color: bgRoot.colText
|
||||
font.pixelSize: Appearance.font.pixelSize.larger
|
||||
style: Text.Raised
|
||||
styleColor: Appearance.colors.colShadow
|
||||
ClockStatusText {
|
||||
shown: GlobalStates.screenLocked && (!Config.options.background.lockBlur.enable || Config.options.background.lockBlur.showLockedText)
|
||||
statusIcon: "lock"
|
||||
statusText: qsTr("Locked")
|
||||
}
|
||||
Item { Layout.fillWidth: bgRoot.textHorizontalAlignment !== Text.AlignRight; implicitWidth: 1 }
|
||||
|
||||
|
||||
@@ -128,6 +128,8 @@ Singleton {
|
||||
property bool showClock: true
|
||||
property string wallpaperPath: ""
|
||||
property string thumbnailPath: ""
|
||||
property string quote: ""
|
||||
property bool hideWhenFullscreen: true
|
||||
property JsonObject parallax: JsonObject {
|
||||
property bool vertical: false
|
||||
property bool autoVertical: false
|
||||
@@ -142,8 +144,13 @@ Singleton {
|
||||
property bool showLockedText: true
|
||||
property real extraZoom: 1.1
|
||||
}
|
||||
property string quote: ""
|
||||
property bool hideWhenFullscreen: true
|
||||
property JsonObject wallpaperSafety: JsonObject {
|
||||
property bool enable: true
|
||||
property JsonObject triggerCondition: JsonObject {
|
||||
property list<string> wallpaperKeywords: ["anime", "ecchi", "hentai", "yande.re", "konachan", "breast", "nipples", "pussy", "nsfw", "spoiler", "girl"]
|
||||
property list<string> networkNameKeywords: ["guest", "public", "free", "airport"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property JsonObject bar: JsonObject {
|
||||
|
||||
@@ -8,7 +8,7 @@ Singleton {
|
||||
* Formats a string according to the args that are passed inc
|
||||
* @param { string } str
|
||||
* @param {...any} args
|
||||
* @returns
|
||||
* @returns { string }
|
||||
*/
|
||||
function format(str, ...args) {
|
||||
return str.replace(/{(\d+)}/g, (match, index) => typeof args[index] !== 'undefined' ? args[index] : match);
|
||||
@@ -35,10 +35,10 @@ Singleton {
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes single quotes in shell commands
|
||||
* @param { string } str
|
||||
* @returns { string }
|
||||
*/
|
||||
* Escapes single quotes in shell commands
|
||||
* @param { string } str
|
||||
* @returns { string }
|
||||
*/
|
||||
function shellSingleQuoteEscape(str) {
|
||||
return String(str)
|
||||
// .replace(/\\/g, '\\\\')
|
||||
@@ -48,6 +48,7 @@ Singleton {
|
||||
/**
|
||||
* Splits markdown blocks into three different types: text, think, and code.
|
||||
* @param { string } markdown
|
||||
* @returns {Array<{type: "text" | "think" | "code", content: string, lang?: string, completed?: boolean}>}
|
||||
*/
|
||||
function splitMarkdownBlocks(markdown) {
|
||||
const regex = /```(\w+)?\n([\s\S]*?)```|<think>([\s\S]*?)<\/think>/g;
|
||||
@@ -182,6 +183,11 @@ Singleton {
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up a music title by removing bracketed and special characters.
|
||||
* @param { string } title
|
||||
* @returns { string }
|
||||
*/
|
||||
function cleanMusicTitle(title) {
|
||||
if (!title)
|
||||
return "";
|
||||
@@ -198,6 +204,11 @@ Singleton {
|
||||
return title.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts seconds to a friendly time string (e.g. 1:23 or 1:02:03).
|
||||
* @param { number } seconds
|
||||
* @returns { string }
|
||||
*/
|
||||
function friendlyTimeForSeconds(seconds) {
|
||||
if (isNaN(seconds) || seconds < 0)
|
||||
return "0:00";
|
||||
@@ -212,13 +223,38 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes HTML special characters in a string.
|
||||
* @param { string } str
|
||||
* @returns { string }
|
||||
*/
|
||||
function escapeHtml(str) {
|
||||
if (typeof str !== 'string')
|
||||
return str;
|
||||
return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''');
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans a cliphist entry by removing leading digits and tab.
|
||||
* @param { string } str
|
||||
* @returns { string }
|
||||
*/
|
||||
function cleanCliphistEntry(str: string): string {
|
||||
return str.replace(/^\d+\t/, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if any substring in the list is contained in the string.
|
||||
* @param { string } str
|
||||
* @param { string[] } substrings
|
||||
* @returns { boolean }
|
||||
*/
|
||||
function stringListContainsSubstring(str, substrings) {
|
||||
for (let i = 0; i < substrings.length; ++i) {
|
||||
if (str.includes(substrings[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user