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(".avi")
|
||||||
|| Config.options.background.wallpaperPath.endsWith(".mov")
|
|| Config.options.background.wallpaperPath.endsWith(".mov")
|
||||||
property string wallpaperPath: wallpaperIsVideo ? Config.options.background.thumbnailPath : Config.options.background.wallpaperPath
|
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 wallpaperToScreenRatio: Math.min(wallpaperWidth / screen.width, wallpaperHeight / screen.height)
|
||||||
property real preferredWallpaperScale: Config.options.background.parallax.workspaceZoom
|
property real preferredWallpaperScale: Config.options.background.parallax.workspaceZoom
|
||||||
property real effectiveWallpaperScale: 1 // Some reasonable init value, to be updated
|
property real effectiveWallpaperScale: 1 // Some reasonable init value, to be updated
|
||||||
@@ -57,7 +61,7 @@ Variants {
|
|||||||
property real clockX: (modelData.width / 2)
|
property real clockX: (modelData.width / 2)
|
||||||
property real clockY: (modelData.height / 2)
|
property real clockY: (modelData.height / 2)
|
||||||
property var textHorizontalAlignment: {
|
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;
|
return Text.AlignHCenter;
|
||||||
if (clockX < screen.width / 3)
|
if (clockX < screen.width / 3)
|
||||||
return Text.AlignLeft;
|
return Text.AlignLeft;
|
||||||
@@ -69,11 +73,61 @@ Variants {
|
|||||||
property bool shouldBlur: (GlobalStates.screenLocked && Config.options.background.lockBlur.enable)
|
property bool shouldBlur: (GlobalStates.screenLocked && Config.options.background.lockBlur.enable)
|
||||||
property color dominantColor: Appearance.colors.colPrimary
|
property color dominantColor: Appearance.colors.colPrimary
|
||||||
property bool dominantColorIsDark: dominantColor.hslLightness < 0.5
|
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 {
|
Behavior on colText {
|
||||||
animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this)
|
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
|
// Layer props
|
||||||
screen: modelData
|
screen: modelData
|
||||||
exclusionMode: ExclusionMode.Ignore
|
exclusionMode: ExclusionMode.Ignore
|
||||||
@@ -86,7 +140,10 @@ Variants {
|
|||||||
left: true
|
left: true
|
||||||
right: 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: {
|
onWallpaperPathChanged: {
|
||||||
bgRoot.updateZoomScale()
|
bgRoot.updateZoomScale()
|
||||||
@@ -206,7 +263,12 @@ Variants {
|
|||||||
property real effectiveValueY: Math.max(0, Math.min(1, valueY))
|
property real effectiveValueY: Math.max(0, Math.min(1, valueY))
|
||||||
x: -(bgRoot.movableXSpace) - (effectiveValueX - 0.5) * 2 * bgRoot.movableXSpace
|
x: -(bgRoot.movableXSpace) - (effectiveValueX - 0.5) * 2 * bgRoot.movableXSpace
|
||||||
y: -(bgRoot.movableYSpace) - (effectiveValueY - 0.5) * 2 * bgRoot.movableYSpace
|
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
|
fillMode: Image.PreserveAspectCrop
|
||||||
Behavior on x {
|
Behavior on x {
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
@@ -278,13 +340,14 @@ Variants {
|
|||||||
}
|
}
|
||||||
states: State {
|
states: State {
|
||||||
name: "centered"
|
name: "centered"
|
||||||
when: bgRoot.shouldBlur && Config.options.background.lockBlur.centerClock
|
when: (bgRoot.shouldBlur && Config.options.background.lockBlur.centerClock) || bgRoot.wallpaperSafetyTriggered
|
||||||
AnchorChanges {
|
AnchorChanges {
|
||||||
target: clockLoader
|
target: clockLoader
|
||||||
anchors {
|
anchors {
|
||||||
left: undefined
|
left: undefined
|
||||||
right: undefined
|
right: undefined
|
||||||
top: parent.top
|
top: undefined
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
horizontalCenter: parent.horizontalCenter
|
horizontalCenter: parent.horizontalCenter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -306,46 +369,27 @@ Variants {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: 6
|
spacing: 6
|
||||||
|
|
||||||
StyledText {
|
ClockText {
|
||||||
Layout.fillWidth: true
|
font.pixelSize: 90
|
||||||
horizontalAlignment: bgRoot.textHorizontalAlignment
|
|
||||||
font {
|
|
||||||
family: Appearance.font.family.expressive
|
|
||||||
pixelSize: 90
|
|
||||||
weight: Font.Bold
|
|
||||||
}
|
|
||||||
color: bgRoot.colText
|
|
||||||
style: Text.Raised
|
|
||||||
styleColor: Appearance.colors.colShadow
|
|
||||||
text: DateTime.time
|
text: DateTime.time
|
||||||
}
|
}
|
||||||
StyledText {
|
ClockText {
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.topMargin: -5
|
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
|
text: DateTime.date
|
||||||
animateChange: true
|
|
||||||
}
|
}
|
||||||
StyledText {
|
StyledText { // Somehow gets fucked up if made a ClockText???
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
horizontalAlignment: bgRoot.textHorizontalAlignment
|
horizontalAlignment: bgRoot.textHorizontalAlignment
|
||||||
font {
|
font {
|
||||||
family: Appearance.font.family.expressive
|
family: Appearance.font.family.main
|
||||||
pixelSize: 20
|
pixelSize: Appearance.font.pixelSize.normal
|
||||||
weight: Font.DemiBold
|
weight: 350
|
||||||
|
italic: true
|
||||||
}
|
}
|
||||||
color: bgRoot.colText
|
color: bgRoot.colText
|
||||||
style: Text.Raised
|
style: Text.Raised
|
||||||
visible: Config.options.background.quote !== ""
|
|
||||||
styleColor: Appearance.colors.colShadow
|
styleColor: Appearance.colors.colShadow
|
||||||
|
// visible: Config.options.background.quote.length > 0
|
||||||
text: Config.options.background.quote
|
text: Config.options.background.quote
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -356,31 +400,21 @@ Variants {
|
|||||||
left: bgRoot.textHorizontalAlignment === Text.AlignLeft ? clockColumn.left : undefined
|
left: bgRoot.textHorizontalAlignment === Text.AlignLeft ? clockColumn.left : undefined
|
||||||
right: bgRoot.textHorizontalAlignment === Text.AlignRight ? clockColumn.right : undefined
|
right: bgRoot.textHorizontalAlignment === Text.AlignRight ? clockColumn.right : undefined
|
||||||
horizontalCenter: bgRoot.textHorizontalAlignment === Text.AlignHCenter ? clockColumn.horizontalCenter : undefined
|
horizontalCenter: bgRoot.textHorizontalAlignment === Text.AlignHCenter ? clockColumn.horizontalCenter : undefined
|
||||||
topMargin: 5
|
topMargin: 14
|
||||||
leftMargin: -5
|
leftMargin: -6
|
||||||
rightMargin: -5
|
rightMargin: -6
|
||||||
}
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
spacing: 16
|
||||||
Item { Layout.fillWidth: bgRoot.textHorizontalAlignment !== Text.AlignLeft; implicitWidth: 1 }
|
Item { Layout.fillWidth: bgRoot.textHorizontalAlignment !== Text.AlignLeft; implicitWidth: 1 }
|
||||||
MaterialSymbol {
|
ClockStatusText {
|
||||||
text: "lock"
|
shown: bgRoot.wallpaperSafetyTriggered
|
||||||
Layout.fillWidth: false
|
statusIcon: "hide_image"
|
||||||
iconSize: Appearance.font.pixelSize.huge
|
statusText: qsTr("Wallpaper safety enforced")
|
||||||
color: bgRoot.colText
|
|
||||||
style: Text.Raised
|
|
||||||
styleColor: Appearance.colors.colShadow
|
|
||||||
}
|
}
|
||||||
StyledText {
|
ClockStatusText {
|
||||||
Layout.fillWidth: false
|
shown: GlobalStates.screenLocked && (!Config.options.background.lockBlur.enable || Config.options.background.lockBlur.showLockedText)
|
||||||
text: "Locked"
|
statusIcon: "lock"
|
||||||
color: bgRoot.colText
|
statusText: qsTr("Locked")
|
||||||
font.pixelSize: Appearance.font.pixelSize.larger
|
|
||||||
style: Text.Raised
|
|
||||||
styleColor: Appearance.colors.colShadow
|
|
||||||
}
|
}
|
||||||
Item { Layout.fillWidth: bgRoot.textHorizontalAlignment !== Text.AlignRight; implicitWidth: 1 }
|
Item { Layout.fillWidth: bgRoot.textHorizontalAlignment !== Text.AlignRight; implicitWidth: 1 }
|
||||||
|
|
||||||
|
|||||||
@@ -128,6 +128,8 @@ Singleton {
|
|||||||
property bool showClock: true
|
property bool showClock: true
|
||||||
property string wallpaperPath: ""
|
property string wallpaperPath: ""
|
||||||
property string thumbnailPath: ""
|
property string thumbnailPath: ""
|
||||||
|
property string quote: ""
|
||||||
|
property bool hideWhenFullscreen: true
|
||||||
property JsonObject parallax: JsonObject {
|
property JsonObject parallax: JsonObject {
|
||||||
property bool vertical: false
|
property bool vertical: false
|
||||||
property bool autoVertical: false
|
property bool autoVertical: false
|
||||||
@@ -142,8 +144,13 @@ Singleton {
|
|||||||
property bool showLockedText: true
|
property bool showLockedText: true
|
||||||
property real extraZoom: 1.1
|
property real extraZoom: 1.1
|
||||||
}
|
}
|
||||||
property string quote: ""
|
property JsonObject wallpaperSafety: JsonObject {
|
||||||
property bool hideWhenFullscreen: true
|
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 {
|
property JsonObject bar: JsonObject {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ Singleton {
|
|||||||
* Formats a string according to the args that are passed inc
|
* Formats a string according to the args that are passed inc
|
||||||
* @param { string } str
|
* @param { string } str
|
||||||
* @param {...any} args
|
* @param {...any} args
|
||||||
* @returns
|
* @returns { string }
|
||||||
*/
|
*/
|
||||||
function format(str, ...args) {
|
function format(str, ...args) {
|
||||||
return str.replace(/{(\d+)}/g, (match, index) => typeof args[index] !== 'undefined' ? args[index] : match);
|
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
|
* Escapes single quotes in shell commands
|
||||||
* @param { string } str
|
* @param { string } str
|
||||||
* @returns { string }
|
* @returns { string }
|
||||||
*/
|
*/
|
||||||
function shellSingleQuoteEscape(str) {
|
function shellSingleQuoteEscape(str) {
|
||||||
return String(str)
|
return String(str)
|
||||||
// .replace(/\\/g, '\\\\')
|
// .replace(/\\/g, '\\\\')
|
||||||
@@ -48,6 +48,7 @@ Singleton {
|
|||||||
/**
|
/**
|
||||||
* Splits markdown blocks into three different types: text, think, and code.
|
* Splits markdown blocks into three different types: text, think, and code.
|
||||||
* @param { string } markdown
|
* @param { string } markdown
|
||||||
|
* @returns {Array<{type: "text" | "think" | "code", content: string, lang?: string, completed?: boolean}>}
|
||||||
*/
|
*/
|
||||||
function splitMarkdownBlocks(markdown) {
|
function splitMarkdownBlocks(markdown) {
|
||||||
const regex = /```(\w+)?\n([\s\S]*?)```|<think>([\s\S]*?)<\/think>/g;
|
const regex = /```(\w+)?\n([\s\S]*?)```|<think>([\s\S]*?)<\/think>/g;
|
||||||
@@ -182,6 +183,11 @@ Singleton {
|
|||||||
return lines.join("\n");
|
return lines.join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleans up a music title by removing bracketed and special characters.
|
||||||
|
* @param { string } title
|
||||||
|
* @returns { string }
|
||||||
|
*/
|
||||||
function cleanMusicTitle(title) {
|
function cleanMusicTitle(title) {
|
||||||
if (!title)
|
if (!title)
|
||||||
return "";
|
return "";
|
||||||
@@ -198,6 +204,11 @@ Singleton {
|
|||||||
return title.trim();
|
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) {
|
function friendlyTimeForSeconds(seconds) {
|
||||||
if (isNaN(seconds) || seconds < 0)
|
if (isNaN(seconds) || seconds < 0)
|
||||||
return "0:00";
|
return "0:00";
|
||||||
@@ -212,13 +223,38 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escapes HTML special characters in a string.
|
||||||
|
* @param { string } str
|
||||||
|
* @returns { string }
|
||||||
|
*/
|
||||||
function escapeHtml(str) {
|
function escapeHtml(str) {
|
||||||
if (typeof str !== 'string')
|
if (typeof str !== 'string')
|
||||||
return str;
|
return str;
|
||||||
return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''');
|
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 {
|
function cleanCliphistEntry(str: string): string {
|
||||||
return str.replace(/^\d+\t/, "");
|
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