Merge branch 'main' into hefty-hype

This commit is contained in:
end-4
2026-03-27 23:20:08 +01:00
31 changed files with 1279 additions and 352 deletions
@@ -12,11 +12,11 @@ QuickToggleModel {
name: Translation.tr("Night Light")
statusText: (auto ? Translation.tr("Auto, ") : "") + (toggled ? Translation.tr("Active") : Translation.tr("Inactive"))
toggled: Hyprsunset.active
toggled: Hyprsunset.temperatureActive
icon: auto ? "night_sight_auto" : "bedtime"
mainAction: () => {
Hyprsunset.toggle()
Hyprsunset.toggleTemperature()
}
hasMenu: true
@@ -17,6 +17,7 @@ Slider {
id: root
property list<real> stopIndicatorValues: [1]
property list<real> dividerValues: []
enum Configuration {
Wavy = 4,
XS = 12,
@@ -45,6 +46,7 @@ Slider {
property real handleHeight: (configuration === StyledSlider.Configuration.Wavy) ? 24 : Math.max(33, trackWidth + 9)
property real handleWidth: root.pressed ? handlePressedWidth : handleDefaultWidth
property real handleMargins: 4
property real dividerMargins: 2
property real trackDotSize: 3
property bool usePercentTooltip: true
property string tooltipContent: usePercentTooltip ? `${Math.round(((value - from) / (to - from)) * 100)}%` : `${Math.round(value)}`
@@ -94,71 +96,94 @@ Slider {
}
background: Item {
id: background
anchors.verticalCenter: parent.verticalCenter
width: parent.width
anchors.horizontalCenter: parent.horizontalCenter
width: root.width
implicitHeight: trackWidth
property var normalized: root.dividerValues.map(v => (v - root.from) / (root.to - root.from))
property var filtered: normalized.filter(v => Math.abs(v - root.visualPosition) * effectiveDraggingWidth > handleMargins + handleWidth / 2 - dividerMargins)
property var leftValues: [0, ...filtered.filter(v => v < root.visualPosition), root.visualPosition]
property var rightValues: [root.visualPosition, ...filtered.filter(v => v > root.visualPosition), 1]
property var leftWidths: leftValues.map((v, i, a) => a[i + 1] - v).slice(0, -1)
property var rightWidths: rightValues.map((v, i, a) => a[i + 1] - v).slice(0, -1)
// Fill left
Loader {
anchors {
verticalCenter: parent.verticalCenter
left: parent.left
}
width: root.handleMargins + (root.visualPosition * root.effectiveDraggingWidth) - (root.handleWidth / 2 + root.handleMargins)
height: root.trackWidth
active: !root.wavy
sourceComponent: Rectangle {
color: root.highlightColor
topLeftRadius: root.trackRadius
bottomLeftRadius: root.trackRadius
topRightRadius: root.unsharpenRadius
bottomRightRadius: root.unsharpenRadius
Repeater {
model: background.leftWidths.length
Loader {
required property real index
anchors.verticalCenter: background.verticalCenter
property real leftMargin: index > 0 ? root.dividerMargins : 0
property real rightMargin: index < background.leftWidths.length - 1 ? root.dividerMargins : root.handleMargins
x: background.leftValues[index] * root.effectiveDraggingWidth + leftMargin + (index > 0 ? leftPadding : 0)
width: background.leftWidths[index] * root.effectiveDraggingWidth - leftMargin - rightMargin - (index === background.leftWidths.length - 1 ? handleWidth / 2 : 0) + (index === 0 ? leftPadding : 0)
height: root.trackWidth
active: !root.wavy
sourceComponent: Rectangle {
color: root.highlightColor
topLeftRadius: index === 0 ? root.trackRadius : root.unsharpenRadius
bottomLeftRadius: index === 0 ? root.trackRadius : root.unsharpenRadius
topRightRadius: root.unsharpenRadius
bottomRightRadius: root.unsharpenRadius
}
}
}
Loader {
anchors {
verticalCenter: parent.verticalCenter
left: parent.left
}
width: root.handleMargins + (root.visualPosition * root.effectiveDraggingWidth) - (root.handleWidth / 2 + root.handleMargins)
height: root.height
active: root.wavy
sourceComponent: WavyLine {
id: wavyFill
frequency: root.waveFrequency
fullLength: root.width
color: root.highlightColor
amplitudeMultiplier: root.wavy ? 0.5 : 0
width: root.handleMargins + (root.visualPosition * root.effectiveDraggingWidth) - (root.handleWidth / 2 + root.handleMargins)
height: root.trackWidth
Connections {
target: root
function onValueChanged() { wavyFill.requestPaint(); }
function onHighlightColorChanged() { wavyFill.requestPaint(); }
}
FrameAnimation {
running: root.animateWave
onTriggered: {
wavyFill.requestPaint()
Repeater {
model: background.leftWidths.length
Loader {
required property int index
anchors.verticalCenter: background.verticalCenter
property real leftMargin: index > 0 ? root.dividerMargins : 0
property real rightMargin: index < background.leftWidths.length - 1 ? root.dividerMargins : root.handleMargins
x: background.leftValues[index] * root.effectiveDraggingWidth + leftMargin + (index > 0 ? leftPadding : 0)
width: background.leftWidths[index] * root.effectiveDraggingWidth - leftMargin - rightMargin - (index === background.leftWidths.length - 1 ? handleWidth / 2 : 0) + (index === 0 ? leftPadding : 0)
height: root.height
active: root.wavy
sourceComponent: WavyLine {
id: wavyFill
frequency: root.waveFrequency
fullLength: root.width
color: root.highlightColor
amplitudeMultiplier: root.wavy ? 0.5 : 0
width: parent.width
height: root.trackWidth
Connections {
target: root
function onValueChanged() { wavyFill.requestPaint(); }
function onHighlightColorChanged() { wavyFill.requestPaint(); }
}
FrameAnimation {
running: root.animateWave
onTriggered: {
wavyFill.requestPaint()
}
}
}
}
}
}
// Fill right
Rectangle {
anchors {
verticalCenter: parent.verticalCenter
right: parent.right
Repeater {
model: background.rightWidths.length
Rectangle {
required property int index
anchors.verticalCenter: background.verticalCenter
property real leftMargin: index > 0 ? root.dividerMargins : root.handleMargins
property real rightMargin: index < background.rightWidths.length - 1 ? root.dividerMargins : 0
x: background.rightValues[index] * root.effectiveDraggingWidth + leftMargin + (index === 0 ? handleWidth / 2 : 0) + leftPadding
width: background.rightWidths[index] * root.effectiveDraggingWidth - leftMargin - rightMargin - (index === 0 ? handleWidth / 2 : 0) + (index === background.rightWidths.length - 1 ? rightPadding : 0)
height: trackWidth
color: root.trackColor
topRightRadius: index === background.rightWidths.length - 1 ? root.trackRadius : root.unsharpenRadius
bottomRightRadius: index === background.rightWidths.length - 1 ? root.trackRadius : root.unsharpenRadius
topLeftRadius: root.unsharpenRadius
bottomLeftRadius: root.unsharpenRadius
}
width: root.handleMargins + ((1 - root.visualPosition) * root.effectiveDraggingWidth) - (root.handleWidth / 2 + root.handleMargins)
height: trackWidth
color: root.trackColor
topRightRadius: root.trackRadius
bottomRightRadius: root.trackRadius
topLeftRadius: root.unsharpenRadius
bottomLeftRadius: root.unsharpenRadius
}
// Stop indicators
@@ -177,7 +202,7 @@ Slider {
implicitWidth: root.handleWidth
implicitHeight: root.handleHeight
x: root.handleMargins + (root.visualPosition * root.effectiveDraggingWidth) - (root.handleWidth / 2)
x: root.leftPadding + (root.visualPosition * root.effectiveDraggingWidth) - (root.handleWidth / 2)
anchors.verticalCenter: parent.verticalCenter
radius: Appearance.rounding.full
color: root.handleColor
@@ -59,8 +59,8 @@ Item { // Bar content region
implicitWidth: leftSectionRowLayout.implicitWidth
implicitHeight: Appearance.sizes.baseBarHeight
onScrollDown: root.brightnessMonitor.setBrightness(root.brightnessMonitor.brightness - 0.05)
onScrollUp: root.brightnessMonitor.setBrightness(root.brightnessMonitor.brightness + 0.05)
onScrollDown: Brightness.decreaseBrightness()
onScrollUp: Brightness.increaseBrightness()
onMovedAway: GlobalStates.osdBrightnessOpen = false
onPressed: event => {
if (event.button === Qt.LeftButton)
@@ -70,7 +70,7 @@ Item { // Bar content region
// Visual content
ScrollHint {
reveal: barLeftSideMouseArea.hovered
icon: "light_mode"
icon: Hyprsunset.gamma === 100 ? "light_mode" : "wb_twilight"
tooltipText: Translation.tr("Scroll to change brightness")
side: "left"
anchors.left: parent.left
@@ -25,6 +25,10 @@ Scope {
id: "brightness",
sourceUrl: "indicators/BrightnessIndicator.qml"
},
{
id: "gamma",
sourceUrl: "indicators/GammaIndicator.qml"
},
]
function triggerOsd() {
@@ -52,6 +56,15 @@ Scope {
}
}
Connections {
target: Hyprsunset
function onGammaChangeAttempt() {
root.protectionMessage = "";
root.currentIndicator = "gamma";
root.triggerOsd();
}
}
Connections {
// Listen to volume changes
target: Audio.sink?.audio ?? null
@@ -11,6 +11,8 @@ Item {
required property string name
property bool rotateIcon: false
property bool scaleIcon: false
property alias from: valueProgressBar.from
property alias to: valueProgressBar.to
property real valueIndicatorVerticalPadding: 9
property real valueIndicatorLeftPadding: 10
@@ -9,7 +9,7 @@ OsdValueIndicator {
property var focusedScreen: Quickshell.screens.find(s => s.name === Hyprland.focusedMonitor?.name)
property var brightnessMonitor: Brightness.getMonitorForScreen(focusedScreen)
icon: Hyprsunset.active ? "routine" : "light_mode"
icon: Hyprsunset.temperatureActive ? "routine" : "light_mode"
rotateIcon: true
scaleIcon: true
name: Translation.tr("Brightness")
@@ -0,0 +1,14 @@
import qs.services
import QtQuick
import Quickshell
import Quickshell.Hyprland
import qs.modules.ii.onScreenDisplay
OsdValueIndicator {
id: rotateIcon
icon: "wb_twilight"
name: Translation.tr("Gamma")
from: Hyprsunset.gammaLowerLimit / 100
value: Hyprsunset.gamma / 100 ?? 0.5
}
@@ -240,7 +240,7 @@ Item {
}
}
z: Drag.active ? root.windowDraggingZ : (root.windowZ + windowData?.floating)
z: Drag.active ? root.windowDraggingZ : (root.windowZ + windowData?.floating + windowData?.fullscreen * 2)
Drag.hotSpot.x: width / 2
Drag.hotSpot.y: height / 2
MouseArea {
@@ -98,7 +98,7 @@ Scope {
if (!Config.options.sidebar.cornerOpen.valueScroll)
return;
if (cornerWidget.isLeft)
cornerPanelWindow.brightnessMonitor.setBrightness(cornerPanelWindow.brightnessMonitor.brightness - 0.05);
Brightness.decreaseBrightness()
else {
const currentVolume = Audio.value;
const step = currentVolume < 0.1 ? 0.01 : 0.02 || 0.2;
@@ -109,7 +109,7 @@ Scope {
if (!Config.options.sidebar.cornerOpen.valueScroll)
return;
if (cornerWidget.isLeft)
cornerPanelWindow.brightnessMonitor.setBrightness(cornerPanelWindow.brightnessMonitor.brightness + 0.05);
Brightness.increaseBrightness()
else {
const currentVolume = Audio.value;
const step = currentVolume < 0.1 ? 0.01 : 0.02 || 0.2;
@@ -497,199 +497,206 @@ Inline w/ backslash and round brackets \\(e^{i\\pi} + 1 = 0\\)
RowLayout { // Input field and send button
id: inputFieldRowLayout
anchors {
top: attachedFileIndicator.bottom
bottom: commandButtonsRow.top
left: parent.left
right: parent.right
topMargin: 5
bottomMargin: 5
}
spacing: 0
StyledTextArea { // The actual TextArea
id: messageInputField
wrapMode: TextArea.Wrap
ScrollView {
id: inputScrollView
Layout.fillWidth: true
padding: 10
color: activeFocus ? Appearance.m3colors.m3onSurface : Appearance.m3colors.m3onSurfaceVariant
placeholderText: Translation.tr('Message the model... "%1" for commands').arg(root.commandPrefix)
Layout.preferredHeight: Math.min(root.height * 3/5, messageInputField.height)
clip: true
ScrollBar.vertical.policy: ScrollBar.AsNeeded
background: null
StyledTextArea { // The actual TextArea (inside ScrollView to enable scrolling)
id: messageInputField
anchors.fill: parent
wrapMode: TextArea.Wrap
padding: 10
color: activeFocus ? Appearance.m3colors.m3onSurface : Appearance.m3colors.m3onSurfaceVariant
placeholderText: Translation.tr('Message the model... "%1" for commands').arg(root.commandPrefix)
onTextChanged: {
// Handle suggestions
if (messageInputField.text.length === 0) {
root.suggestionQuery = "";
root.suggestionList = [];
return;
} else if (messageInputField.text.startsWith(`${root.commandPrefix}model`)) {
root.suggestionQuery = messageInputField.text.split(" ")[1] ?? "";
const modelResults = Fuzzy.go(root.suggestionQuery, Ai.modelList.map(model => {
return {
name: Fuzzy.prepare(model),
obj: model
};
}), {
all: true,
key: "name"
});
root.suggestionList = modelResults.map(model => {
return {
name: `${messageInputField.text.trim().split(" ").length == 1 ? (root.commandPrefix + "model ") : ""}${model.target}`,
displayName: `${Ai.models[model.target].name}`,
description: `${Ai.models[model.target].description}`
};
});
} else if (messageInputField.text.startsWith(`${root.commandPrefix}prompt`)) {
root.suggestionQuery = messageInputField.text.split(" ")[1] ?? "";
const promptFileResults = Fuzzy.go(root.suggestionQuery, Ai.promptFiles.map(file => {
return {
name: Fuzzy.prepare(file),
obj: file
};
}), {
all: true,
key: "name"
});
root.suggestionList = promptFileResults.map(file => {
return {
name: `${messageInputField.text.trim().split(" ").length == 1 ? (root.commandPrefix + "prompt ") : ""}${file.target}`,
displayName: `${FileUtils.trimFileExt(FileUtils.fileNameForPath(file.target))}`,
description: Translation.tr("Load prompt from %1").arg(file.target)
};
});
} else if (messageInputField.text.startsWith(`${root.commandPrefix}save`)) {
root.suggestionQuery = messageInputField.text.split(" ")[1] ?? "";
const promptFileResults = Fuzzy.go(root.suggestionQuery, Ai.savedChats.map(file => {
return {
name: Fuzzy.prepare(file),
obj: file
};
}), {
all: true,
key: "name"
});
root.suggestionList = promptFileResults.map(file => {
const chatName = FileUtils.trimFileExt(FileUtils.fileNameForPath(file.target)).trim();
return {
name: `${messageInputField.text.trim().split(" ").length == 1 ? (root.commandPrefix + "save ") : ""}${chatName}`,
displayName: `${chatName}`,
description: Translation.tr("Save chat to %1").arg(chatName)
};
});
} else if (messageInputField.text.startsWith(`${root.commandPrefix}load`)) {
root.suggestionQuery = messageInputField.text.split(" ")[1] ?? "";
const promptFileResults = Fuzzy.go(root.suggestionQuery, Ai.savedChats.map(file => {
return {
name: Fuzzy.prepare(file),
obj: file
};
}), {
all: true,
key: "name"
});
root.suggestionList = promptFileResults.map(file => {
const chatName = FileUtils.trimFileExt(FileUtils.fileNameForPath(file.target)).trim();
return {
name: `${messageInputField.text.trim().split(" ").length == 1 ? (root.commandPrefix + "load ") : ""}${chatName}`,
displayName: `${chatName}`,
description: Translation.tr(`Load chat from %1`).arg(file.target)
};
});
} else if (messageInputField.text.startsWith(`${root.commandPrefix}tool`)) {
root.suggestionQuery = messageInputField.text.split(" ")[1] ?? "";
const toolResults = Fuzzy.go(root.suggestionQuery, Ai.availableTools.map(tool => {
return {
name: Fuzzy.prepare(tool),
obj: tool
};
}), {
all: true,
key: "name"
});
root.suggestionList = toolResults.map(tool => {
const toolName = tool.target;
return {
name: `${messageInputField.text.trim().split(" ").length == 1 ? (root.commandPrefix + "tool ") : ""}${tool.target}`,
displayName: toolName,
description: Ai.toolDescriptions[toolName]
};
});
} else if (messageInputField.text.startsWith(root.commandPrefix)) {
root.suggestionQuery = messageInputField.text;
root.suggestionList = root.allCommands.filter(cmd => cmd.name.startsWith(messageInputField.text.substring(1))).map(cmd => {
return {
name: `${root.commandPrefix}${cmd.name}`,
description: `${cmd.description}`
};
});
background: null
onTextChanged: {
// Handle suggestions
if (messageInputField.text.length === 0) {
root.suggestionQuery = "";
root.suggestionList = [];
return;
} else if (messageInputField.text.startsWith(`${root.commandPrefix}model`)) {
root.suggestionQuery = messageInputField.text.split(" ")[1] ?? "";
const modelResults = Fuzzy.go(root.suggestionQuery, Ai.modelList.map(model => {
return {
name: Fuzzy.prepare(model),
obj: model
};
}), {
all: true,
key: "name"
});
root.suggestionList = modelResults.map(model => {
return {
name: `${messageInputField.text.trim().split(" ").length == 1 ? (root.commandPrefix + "model ") : ""}${model.target}`,
displayName: `${Ai.models[model.target].name}`,
description: `${Ai.models[model.target].description}`
};
});
} else if (messageInputField.text.startsWith(`${root.commandPrefix}prompt`)) {
root.suggestionQuery = messageInputField.text.split(" ")[1] ?? "";
const promptFileResults = Fuzzy.go(root.suggestionQuery, Ai.promptFiles.map(file => {
return {
name: Fuzzy.prepare(file),
obj: file
};
}), {
all: true,
key: "name"
});
root.suggestionList = promptFileResults.map(file => {
return {
name: `${messageInputField.text.trim().split(" ").length == 1 ? (root.commandPrefix + "prompt ") : ""}${file.target}`,
displayName: `${FileUtils.trimFileExt(FileUtils.fileNameForPath(file.target))}`,
description: Translation.tr("Load prompt from %1").arg(file.target)
};
});
} else if (messageInputField.text.startsWith(`${root.commandPrefix}save`)) {
root.suggestionQuery = messageInputField.text.split(" ")[1] ?? "";
const promptFileResults = Fuzzy.go(root.suggestionQuery, Ai.savedChats.map(file => {
return {
name: Fuzzy.prepare(file),
obj: file
};
}), {
all: true,
key: "name"
});
root.suggestionList = promptFileResults.map(file => {
const chatName = FileUtils.trimFileExt(FileUtils.fileNameForPath(file.target)).trim();
return {
name: `${messageInputField.text.trim().split(" ").length == 1 ? (root.commandPrefix + "save ") : ""}${chatName}`,
displayName: `${chatName}`,
description: Translation.tr("Save chat to %1").arg(chatName)
};
});
} else if (messageInputField.text.startsWith(`${root.commandPrefix}load`)) {
root.suggestionQuery = messageInputField.text.split(" ")[1] ?? "";
const promptFileResults = Fuzzy.go(root.suggestionQuery, Ai.savedChats.map(file => {
return {
name: Fuzzy.prepare(file),
obj: file
};
}), {
all: true,
key: "name"
});
root.suggestionList = promptFileResults.map(file => {
const chatName = FileUtils.trimFileExt(FileUtils.fileNameForPath(file.target)).trim();
return {
name: `${messageInputField.text.trim().split(" ").length == 1 ? (root.commandPrefix + "load ") : ""}${chatName}`,
displayName: `${chatName}`,
description: Translation.tr(`Load chat from %1`).arg(file.target)
};
});
} else if (messageInputField.text.startsWith(`${root.commandPrefix}tool`)) {
root.suggestionQuery = messageInputField.text.split(" ")[1] ?? "";
const toolResults = Fuzzy.go(root.suggestionQuery, Ai.availableTools.map(tool => {
return {
name: Fuzzy.prepare(tool),
obj: tool
};
}), {
all: true,
key: "name"
});
root.suggestionList = toolResults.map(tool => {
const toolName = tool.target;
return {
name: `${messageInputField.text.trim().split(" ").length == 1 ? (root.commandPrefix + "tool ") : ""}${tool.target}`,
displayName: toolName,
description: Ai.toolDescriptions[toolName]
};
});
} else if (messageInputField.text.startsWith(root.commandPrefix)) {
root.suggestionQuery = messageInputField.text;
root.suggestionList = root.allCommands.filter(cmd => cmd.name.startsWith(messageInputField.text.substring(1))).map(cmd => {
return {
name: `${root.commandPrefix}${cmd.name}`,
description: `${cmd.description}`
};
});
}
}
}
function accept() {
root.handleInput(text);
text = "";
}
function accept() {
root.handleInput(text);
text = "";
}
Keys.onPressed: event => {
if (event.key === Qt.Key_Tab) {
suggestions.acceptSelectedWord();
event.accepted = true;
} else if (event.key === Qt.Key_Up && suggestions.visible) {
suggestions.selectedIndex = Math.max(0, suggestions.selectedIndex - 1);
event.accepted = true;
} else if (event.key === Qt.Key_Down && suggestions.visible) {
suggestions.selectedIndex = Math.min(root.suggestionList.length - 1, suggestions.selectedIndex + 1);
event.accepted = true;
} else if ((event.key === Qt.Key_Enter || event.key === Qt.Key_Return)) {
if (event.modifiers & Qt.ShiftModifier) {
// Insert newline
messageInputField.insert(messageInputField.cursorPosition, "\n");
Keys.onPressed: event => {
if (event.key === Qt.Key_Tab) {
suggestions.acceptSelectedWord();
event.accepted = true;
} else {
// Accept text
const inputText = messageInputField.text;
messageInputField.clear();
root.handleInput(inputText);
} else if (event.key === Qt.Key_Up && suggestions.visible) {
suggestions.selectedIndex = Math.max(0, suggestions.selectedIndex - 1);
event.accepted = true;
}
} else if ((event.modifiers & Qt.ControlModifier) && event.key === Qt.Key_V) {
// Intercept Ctrl+V to handle image/file pasting
if (event.modifiers & Qt.ShiftModifier) {
// Let Shift+Ctrl+V = plain paste
messageInputField.text += Quickshell.clipboardText;
} else if (event.key === Qt.Key_Down && suggestions.visible) {
suggestions.selectedIndex = Math.min(root.suggestionList.length - 1, suggestions.selectedIndex + 1);
event.accepted = true;
return;
}
// Try image paste first
const currentClipboardEntry = Cliphist.entries[0];
const cleanCliphistEntry = StringUtils.cleanCliphistEntry(currentClipboardEntry);
if (/^\d+\t\[\[.*binary data.*\d+x\d+.*\]\]$/.test(currentClipboardEntry)) {
// First entry = currently copied entry = image?
decodeImageAndAttachProc.handleEntry(currentClipboardEntry);
event.accepted = true;
return;
} else if (cleanCliphistEntry.startsWith("file://")) {
// First entry = currently copied entry = image?
const fileName = decodeURIComponent(cleanCliphistEntry);
Ai.attachFile(fileName);
event.accepted = true;
return;
}
event.accepted = false; // No image, let text pasting proceed
} else if (event.key === Qt.Key_Escape) {
// Esc to detach file
if (Ai.pendingFilePath.length > 0) {
Ai.attachFile("");
event.accepted = true;
} else {
event.accepted = false;
} else if ((event.key === Qt.Key_Enter || event.key === Qt.Key_Return)) {
if (event.modifiers & Qt.ShiftModifier) {
// Insert newline
messageInputField.insert(messageInputField.cursorPosition, "\n");
event.accepted = true;
} else {
// Accept text
const inputText = messageInputField.text;
messageInputField.clear();
root.handleInput(inputText);
event.accepted = true;
}
} else if ((event.modifiers & Qt.ControlModifier) && event.key === Qt.Key_V) {
// Intercept Ctrl+V to handle image/file pasting
if (event.modifiers & Qt.ShiftModifier) {
// Let Shift+Ctrl+V = plain paste
messageInputField.text += Quickshell.clipboardText;
event.accepted = true;
return;
}
// Try image paste first
const currentClipboardEntry = Cliphist.entries[0];
const cleanCliphistEntry = StringUtils.cleanCliphistEntry(currentClipboardEntry);
if (/^\d+\t\[\[.*binary data.*\d+x\d+.*\]\]$/.test(currentClipboardEntry)) {
// First entry = currently copied entry = image?
decodeImageAndAttachProc.handleEntry(currentClipboardEntry);
event.accepted = true;
return;
} else if (cleanCliphistEntry.startsWith("file://")) {
// First entry = currently copied entry = image?
const fileName = decodeURIComponent(cleanCliphistEntry);
Ai.attachFile(fileName);
event.accepted = true;
return;
}
event.accepted = false; // No image, let text pasting proceed
} else if (event.key === Qt.Key_Escape) {
// Esc to detach file
if (Ai.pendingFilePath.length > 0) {
Ai.attachFile("");
event.accepted = true;
} else {
event.accepted = false;
}
}
}
}
}
RippleButton { // Send button
id: sendButton
Layout.alignment: Qt.AlignTop
Layout.alignment: Qt.AlignBottom
Layout.rightMargin: 5
implicitWidth: 40
implicitHeight: 40
@@ -40,10 +40,25 @@ Rectangle {
visible: active
active: Config.options.sidebar.quickSliders.showBrightness
sourceComponent: QuickSlider {
materialSymbol: "brightness_6"
value: root.brightnessMonitor.brightness
materialSymbol: "light_mode"
secondaryMaterialSymbol: "wb_twilight"
stopIndicatorValues: Hyprsunset.gamma !== 100 && root.brightnessMonitor?.brightness !== 0 ? [0.3 + root.brightnessMonitor?.brightness * 0.7] : []
value: Hyprsunset.gamma === 100? 0.3 + root.brightnessMonitor?.brightness * 0.7 : (Hyprsunset.gamma - Hyprsunset.gammaLowerLimit) / (100 - Hyprsunset.gammaLowerLimit) * 0.3
tooltipContent: Hyprsunset.gamma === 100 ? `${Math.round(root.brightnessMonitor?.brightness * 100)}%` : `${Translation.tr("Gamma")} ${Hyprsunset.gamma}%`
onMoved: {
root.brightnessMonitor.setBrightness(value)
if (value >= 0.3) {
// 0.3 - 1.0 brightness
root.brightnessMonitor.setBrightness((value - 0.3) / 0.7);
if (Hyprsunset.gamma !== 100) {
Hyprsunset.setGamma(100);
}
} else {
// 0 - 0.3 gamma
if (root.brightnessMonitor.brightness !== 0) {
root.brightnessMonitor.setBrightness(0);
}
Hyprsunset.setGamma((value / 0.3 * (100 - Hyprsunset.gammaLowerLimit) + Hyprsunset.gammaLowerLimit));
}
}
}
}
@@ -84,16 +99,18 @@ Rectangle {
component QuickSlider: StyledSlider {
id: quickSlider
required property string materialSymbol
property string secondaryMaterialSymbol
configuration: StyledSlider.Configuration.M
stopIndicatorValues: []
dividerValues: secondaryMaterialSymbol.length > 0 ? [secondaryIcon.iconLocation] : []
MaterialSymbol {
id: icon
property bool nearFull: quickSlider.value >= 0.9
anchors {
verticalCenter: parent.verticalCenter
right: nearFull ? quickSlider.handle.right : parent.right
rightMargin: quickSlider.nearFull ? 14 : 8
verticalCenter: quickSlider.verticalCenter
right: nearFull ? quickSlider.handle.right : quickSlider.right
rightMargin: nearFull ? 14 : 8
}
iconSize: 20
color: nearFull ? Appearance.colors.colOnPrimary : Appearance.colors.colOnSecondaryContainer
@@ -105,7 +122,25 @@ Rectangle {
Behavior on anchors.rightMargin {
animation: Appearance.animation.elementMoveFast.numberAnimation.createObject(this)
}
}
MaterialSymbol {
id: secondaryIcon
visible: secondaryMaterialSymbol.length > 0
property real iconLocation: 0.3
property bool nearIcon: iconLocation - quickSlider.value <= 0.1 && iconLocation - quickSlider.value > (quickSlider.handleWidth + 8 - 14) / quickSlider.effectiveDraggingWidth
anchors {
verticalCenter: quickSlider.verticalCenter
right: nearIcon ? quickSlider.handle.right : quickSlider.right
rightMargin: nearIcon ? 14 : (1 - iconLocation) * quickSlider.effectiveDraggingWidth + quickSlider.rightPadding + 8
}
iconSize: 20
color: quickSlider.value >= iconLocation - 0.1 ? Appearance.colors.colOnPrimary : Appearance.colors.colOnSecondaryContainer
text: secondaryMaterialSymbol
Behavior on color {
animation: Appearance.animation.elementMoveFast.colorAnimation.createObject(this)
}
}
}
}
@@ -1,4 +1,5 @@
import qs.modules.common
import qs.modules.common.functions
import qs.modules.common.widgets
import qs.services
import QtQuick
@@ -82,6 +83,22 @@ DialogListItem {
Item {
Layout.fillWidth: true
}
ActionButton {
readonly property bool p: root.device?.paired ?? false
colBackground: p ? Appearance.colors.colError : ColorUtils.transparentize(Appearance.colors.colLayer3, 1)
colBackgroundHover: p ? Appearance.colors.colErrorHover : ColorUtils.transparentize(Appearance.colors.colLayer3, 1)
colRipple: p ? Appearance.colors.colErrorActive : Appearance.colors.colLayer3Hover
colText: p ? Appearance.colors.colOnError : Appearance.colors.colPrimary
buttonText: p ? Translation.tr("Forget") : Translation.tr("Always connect")
onClicked: {
if (root.device?.paired) {
root.device?.forget();
} else {
root.device?.pair();
}
}
}
ActionButton {
buttonText: root.device?.connected ? Translation.tr("Disconnect") : Translation.tr("Connect")
@@ -93,18 +110,6 @@ DialogListItem {
}
}
}
ActionButton {
visible: root.device?.paired ?? false
colBackground: Appearance.colors.colError
colBackgroundHover: Appearance.colors.colErrorHover
colRipple: Appearance.colors.colErrorActive
colText: Appearance.colors.colOnError
buttonText: Translation.tr("Forget")
onClicked: {
root.device?.forget();
}
}
}
Item {
Layout.fillHeight: true
@@ -15,7 +15,7 @@ WindowDialog {
id: root
property var screen: root.QsWindow.window?.screen
property var brightnessMonitor: Brightness.getMonitorForScreen(screen)
backgroundHeight: 600
backgroundHeight: 700
WindowDialogTitle {
text: Translation.tr("Eye protection")
@@ -44,9 +44,9 @@ WindowDialog {
iconSize: Appearance.font.pixelSize.larger
buttonIcon: "check"
text: Translation.tr("Enable now")
checked: Hyprsunset.active
checked: Hyprsunset.temperatureActive
onCheckedChanged: {
Hyprsunset.toggle(checked)
Hyprsunset.toggleTemperature(checked)
}
}
@@ -146,6 +146,33 @@ WindowDialog {
id: brightnessColumn
Layout.topMargin: -16
Layout.fillWidth: true
WindowDialogSlider {
anchors {
left: parent.left
right: parent.right
leftMargin: 4
rightMargin: 4
}
value: root.brightnessMonitor.brightness
onMoved: root.brightnessMonitor.setBrightness(value)
}
}
WindowDialogSectionHeader {
text: Translation.tr("Gamma")
}
WindowDialogSeparator {
Layout.topMargin: -22
Layout.leftMargin: 0
Layout.rightMargin: 0
}
Column {
id: gammaColumn
Layout.topMargin: -16
Layout.fillWidth: true
Layout.fillHeight: true
WindowDialogSlider {
@@ -155,9 +182,10 @@ WindowDialog {
leftMargin: 4
rightMargin: 4
}
// text: Translation.tr("Brightness")
value: root.brightnessMonitor.brightness
onMoved: root.brightnessMonitor.setBrightness(value)
from: Hyprsunset.gammaLowerLimit / 100
value: Hyprsunset.gamma / 100
onMoved: Hyprsunset.setGamma(value * 100)
tooltipContent: `${Math.round(value * 100)}%`
}
}
@@ -6,10 +6,10 @@ import Quickshell.Io
QuickToggleButton {
id: nightLightButton
toggled: Hyprsunset.active
toggled: Hyprsunset.temperatureActive
buttonIcon: Config.options.light.night.automatic ? "night_sight_auto" : "bedtime"
onClicked: {
Hyprsunset.toggle()
Hyprsunset.toggleTemperature()
}
altAction: () => {
@@ -54,8 +54,8 @@ Item { // Bar content region
height: (root.height - middleSection.height) / 2
width: Appearance.sizes.verticalBarWidth
onScrollDown: root.brightnessMonitor.setBrightness(root.brightnessMonitor.brightness - 0.05)
onScrollUp: root.brightnessMonitor.setBrightness(root.brightnessMonitor.brightness + 0.05)
onScrollDown: Brightness.decreaseBrightness()
onScrollUp: Brightness.increaseBrightness()
onMovedAway: GlobalStates.osdBrightnessOpen = false
onPressed: event => {
if (event.button === Qt.LeftButton)
@@ -303,7 +303,7 @@ ContentPage {
Config.options.background.widgets.clock.cookie.useSineCookie = checked;
}
StyledToolTip {
text: "Looks a bit softer and more consistent with different number of sides,\nbut has less impressive morphing"
text: Translation.tr("Looks a bit softer and more consistent with different number of sides,\nbut has less impressive morphing")
}
}
@@ -327,7 +327,7 @@ ContentPage {
Config.options.background.widgets.clock.cookie.constantlyRotate = checked;
}
StyledToolTip {
text: "Makes the clock always rotate. This is extremely expensive\n(expect 50% usage on Intel UHD Graphics) and thus impractical."
text: Translation.tr("Makes the clock always rotate. This is extremely expensive\n(expect 50% usage on Intel UHD Graphics) and thus impractical.")
}
}
@@ -345,7 +345,7 @@ ContentPage {
Config.options.background.widgets.clock.cookie.hourMarks = checked;
}
StyledToolTip {
text: "Can only be turned on using the 'Dots' or 'Full' dial style for aesthetic reasons"
text: Translation.tr("Can only be turned on using the 'Dots' or 'Full' dial style for aesthetic reasons")
}
}
@@ -361,7 +361,7 @@ ContentPage {
Config.options.background.widgets.clock.cookie.timeIndicators = checked;
}
StyledToolTip {
text: "Can't be turned on when using 'Numbers' dial style for aesthetic reasons"
text: Translation.tr("Can't be turned on when using 'Numbers' dial style for aesthetic reasons")
}
}
}
@@ -87,9 +87,9 @@ Item {
name: Translation.tr("Enable now")
description: Translation.tr("More comfortable viewing at night")
iconName: WIcons.nightLightIcon
checked: Hyprsunset.active
checked: Hyprsunset.temperatureActive
onCheckedChanged: {
Hyprsunset.toggle(checked);
Hyprsunset.toggleTemperature(checked);
}
}
@@ -71,7 +71,7 @@ Singleton {
property string bluetoothIcon: BluetoothStatus.connected ? "bluetooth-connected" : BluetoothStatus.enabled ? "bluetooth" : "bluetooth-disabled"
property string nightLightIcon: Hyprsunset.active ? "weather-moon" : "weather-moon-off"
property string nightLightIcon: Hyprsunset.temperatureActive ? "weather-moon" : "weather-moon-off"
property string notificationsIcon: Notifications.silent ? "alert-snooze" : "alert"
@@ -28,6 +28,12 @@ Singleton {
}
function increaseBrightness(): void {
// if gamma is not yet 100, first increase gamma
if (Hyprsunset.gamma !== 100) {
Hyprsunset.setGamma(Hyprsunset.gamma + 5);
return;
}
const focusedName = Hyprland.focusedMonitor.name;
const monitor = monitors.find(m => focusedName === m.screen.name);
if (monitor)
@@ -37,8 +43,12 @@ Singleton {
function decreaseBrightness(): void {
const focusedName = Hyprland.focusedMonitor.name;
const monitor = monitors.find(m => focusedName === m.screen.name);
if (monitor)
if (monitor && monitor.brightness > 0)
monitor.setBrightness(monitor.brightness - 0.05);
// if brightness is 0, then decrease gamma
else {
Hyprsunset.setGamma(Hyprsunset.gamma - 5);
}
}
reloadableId: "brightness"
@@ -13,13 +13,18 @@ import Quickshell.Hyprland
*/
Singleton {
id: root
signal gammaChangeAttempt()
readonly property real gammaLowerLimit: 25
property string from: Config.options?.light?.night?.from ?? "19:00"
property string to: Config.options?.light?.night?.to ?? "06:30"
property bool automatic: Config.options?.light?.night?.automatic && (Config?.ready ?? true)
property int colorTemperature: Config.options?.light?.night?.colorTemperature ?? 5000
property int gamma: 100
property bool shouldBeOn
property bool firstEvaluation: true
property bool active: false
property bool temperatureActive: false
property int fromHour: Number(from.split(":")[0])
property int fromMinute: Number(from.split(":")[1])
@@ -71,24 +76,52 @@ Singleton {
if (!root.automatic || root.manualActive !== undefined)
return;
if (root.shouldBeOn) {
root.enable();
root.enableTemperature();
} else {
root.disable();
root.disableTemperature();
}
}
function load() { } // Dummy to force init
function enable() {
root.active = true;
// console.log("[Hyprsunset] Enabling");
Quickshell.execDetached(["bash", "-c", `pidof hyprsunset || hyprsunset --temperature ${root.colorTemperature}`]);
function startHyprsunset() {
Quickshell.execDetached(["bash", "-c", `pidof hyprsunset || hyprsunset`]);
}
function disable() {
root.active = false;
function load() {
root.startHyprsunset();
updateHyprsunset.restart();
}
Timer {
id: updateHyprsunset
interval: 100
repeat: false
onTriggered: {
root.ensureState();
root.setGamma(root.gamma);
}
}
function enableTemperature() {
root.temperatureActive = true;
// console.log("[Hyprsunset] Enabling");
root.startHyprsunset();
Quickshell.execDetached(["bash", "-c", `hyprctl hyprsunset temperature ${root.colorTemperature}`]);
}
function disableTemperature() {
root.temperatureActive = false;
// console.log("[Hyprsunset] Disabling");
Quickshell.execDetached(["bash", "-c", `pkill hyprsunset`]);
Quickshell.execDetached(["hyprctl", "hyprsunset", "identity"]);
}
function setGamma(gamma) {
root.gamma = Math.max(root.gammaLowerLimit, Math.min(100, gamma));
root.gammaChangeAttempt();
root.startHyprsunset();
Quickshell.execDetached(["bash", "-c", `hyprctl hyprsunset gamma ${root.gamma}`]);
}
function fetchState() {
@@ -104,26 +137,26 @@ Singleton {
onStreamFinished: {
const output = stateCollector.text.trim();
if (output.length == 0 || output.startsWith("Couldn't"))
root.active = false;
root.temperatureActive = false;
else
root.active = (output != "6500"); // 6500 is the default when off
// console.log("[Hyprsunset] Fetched state:", output, "->", root.active);
root.temperatureActive = (output != "6500"); // 6500 is the default when off
// console.log("[Hyprsunset] Fetched state:", output, "->", root.temperatureActive);
}
}
}
function toggle(active = undefined) {
function toggleTemperature(active = undefined) {
if (root.manualActive === undefined) {
root.manualActive = root.active;
root.manualActive = root.temperatureActive;
root.manualActiveHour = root.clockHour;
root.manualActiveMinute = root.clockMinute;
}
root.manualActive = active !== undefined ? active : !root.manualActive;
if (root.manualActive) {
root.enable();
root.enableTemperature();
} else {
root.disable();
root.disableTemperature();
}
}
@@ -131,9 +164,9 @@ Singleton {
Connections {
target: Config.options.light.night
function onColorTemperatureChanged() {
if (!root.active) return;
if (!root.temperatureActive) return;
Hyprland.dispatch(`hyprctl hyprsunset temperature ${Config.options.light.night.colorTemperature}`);
Quickshell.execDetached(["hyprctl", "hyprsunset", "temperature", `${Config.options.light.night.colorTemperature}`]);
}
}
}
}
@@ -81,6 +81,7 @@
"Unknown function call: %1": "Unknown function call: %1",
"Online | %1's model | Delivers fast, responsive and well-formatted answers. Disadvantages: not very eager to do stuff; might make up unknown function calls": "Online | %1's model | Delivers fast, responsive and well-formatted answers. Disadvantages: not very eager to do stuff; might make up unknown function calls",
"Volume": "Volume",
"Gamma": "Gamma",
"Medium": "Medium",
"Copy code": "Copy code",
"Exceeded max allowed": "Exceeded max allowed",
@@ -359,6 +360,10 @@
"Connect to Wi-Fi": "Connect to Wi-Fi",
"... and %1 more": "... and %1 more",
"Cookie clock settings": "Cookie clock settings",
"Looks a bit softer and more consistent with different number of sides,\nbut has less impressive morphing": "Looks a bit softer and more consistent with different number of sides,\nbut has less impressive morphing",
"Makes the clock always rotate. This is extremely expensive\n(expect 50% usage on Intel UHD Graphics) and thus impractical.": "Makes the clock always rotate. This is extremely expensive\n(expect 50% usage on Intel UHD Graphics) and thus impractical.",
"Can only be turned on using the 'Dots' or 'Full' dial style for aesthetic reasons": "Can only be turned on using the 'Dots' or 'Full' dial style for aesthetic reasons",
"Can't be turned on when using 'Numbers' dial style for aesthetic reasons": "Can't be turned on when using 'Numbers' dial style for aesthetic reasons",
"Brightness and volume": "Brightness and volume",
"Choose file": "Choose file",
"Invalid model. Supported: \n```": "Invalid model. Supported: \n```",
@@ -0,0 +1,749 @@
{
"Dark/Light toggle": "Alternar oscuro/claro",
"There might be a download in progress. Check your Downloads folder.": "Puede haber una descarga en curso. Revisa tu carpeta de Descargas.",
"Authentication": "Autenticación",
"More comfortable viewing at night": "Visualización más cómoda de noche",
"Disconnect": "Desconectar",
"Sunrise": "Amanecer",
"Show notifications": "Mostrar notificaciones",
"Video Recording Path": "Ruta de grabación de video",
"Input device": "Dispositivo de entrada",
"When the previous option is off and this is on,\nyou can still hover the corner's end to open sidebar,\nand the remaining area can be used for volume/brightness scroll": "Cuando la opción anterior está desactivada y esta está activada,\naún puedes pasar el cursor por el extremo de la esquina para abrir la barra lateral,\ny el área restante puede usarse para desplazar el volumen/brillo",
"Save chat": "Guardar chat",
"Bar style": "Estilo de barra",
"Monospace font": "Fuente monoespaciada",
"Show hidden icons": "Mostrar iconos ocultos",
"Work safety": "Seguridad laboral",
"Page %1": "Página %1",
"Illegal increment": "Incremento no permitido",
"New desktop": "Nuevo escritorio",
"Adapts the <b>display (physical screen) brightness</b><br><br>Pros: Less expensive, retains colors<br>Cons: Not immediately responsive<br><br><i>Adjusts display brightness after each Hyprland IPC event</i>": "Adapta el <b>brillo del monitor (pantalla física)</b><br><br>Ventajas: Menos costoso, conserva los colores<br>Desventajas: No responde de inmediato<br><br><i>Ajusta el brillo del monitor tras cada evento IPC de Hyprland</i>",
"Font family name (e.g., JetBrains Mono NF)": "Nombre de familia de fuente (p. ej., JetBrains Mono NF)",
"Open": "Abrir",
"Jump to current month": "Ir al mes actual",
"Shut down": "Apagar",
"Normal": "Normal",
"Fonts": "Fuentes",
"Widgets": "Widgets",
"Set the tool to use for the model.": "Establece la herramienta a usar con el modelo.",
"Bar": "Barra",
"Font width and roundness settings are only available for some fonts like Google Sans Flex": "Los ajustes de ancho y redondez de fuente solo están disponibles para algunas fuentes como Google Sans Flex",
"Hour hand": "Manecilla de hora",
"Use macOS-like symbols for mods keys": "Usar símbolos estilo macOS para teclas modificadoras",
"Unpin from Start": "Desanclar del inicio",
"Connected": "Conectado",
"All": "Todo",
"Invalid tool. Supported tools:\n- %1": "Herramienta no válida. Herramientas compatibles:\n- %1",
"Timer": "Temporizador",
"Bottom": "Abajo",
"Connect": "Conectar",
"Sunset": "Atardecer",
"View Markdown source": "Ver fuente Markdown",
"Cannot find a GPS service. Using the fallback method instead.": "No se encontró un servicio GPS. Usando el método alternativo.",
"Minute hand": "Manecilla de minutos",
"Not all options are available in this app. You should also check the config file by hitting the \"Config file\" button on the topleft corner or opening %1 manually.": "No todas las opciones están disponibles en esta aplicación. También deberías revisar el archivo de configuración haciendo clic en el botón \"Archivo de configuración\" en la esquina superior izquierda o abriendo %1 manualmente.",
"Click to unmute": "Clic para activar el sonido",
"Useless buttons": "Botones inútiles",
"Command rejected by user": "Comando rechazado por el usuario",
"Lock": "Bloquear",
"Expressive font": "Fuente expresiva",
"Security": "Seguridad",
"Sound input": "Entrada de sonido",
"Online | Google's model\nNewer model that's slower than its predecessor but should deliver higher quality answers": "En línea | Modelo de Google\nModelo más reciente, más lento que su predecesor pero con respuestas de mayor calidad",
"Roman": "Romano",
"Style: general": "Estilo: general",
"Numbers font": "Fuente de números",
"Internet": "Internet",
"Date style": "Estilo de fecha",
"When this is off you'll have to click": "Cuando está desactivado tendrás que hacer clic",
"Corner style": "Estilo de esquina",
"Rows": "Filas",
"Tool set to: %1": "Herramienta establecida en: %1",
"Online models disallowed\n\nControlled by `policies.ai` config option": "Modelos en línea no permitidos\n\nControlado por la opción de configuración `policies.ai`",
"Number show delay when pressing Super (ms)": "Retraso para mostrar número al presionar Super (ms)",
"Keep right sidebar loaded": "Mantener la barra lateral derecha cargada",
"Base URL": "URL base",
"Cheat sheet": "Hoja de trucos",
"Recognize music": "Reconocer música",
"Region width": "Ancho de región",
"Wallpaper & Colors": "Fondo de pantalla y colores",
"Sounds": "Sonidos",
"About": "Acerca de",
"Dial style": "Estilo de esfera",
"Classic": "Clásico",
"Translation goes here...": "La traducción va aquí...",
"Widget: Weather": "Widget: Clima",
"Copy": "Copiar",
"Services": "Servicios",
"Dark": "Oscuro",
"The current system prompt is\n\n---\n\n%1": "El prompt de sistema actual es\n\n---\n\n%1",
"Refreshing (manually triggered)": "Actualizando (activado manualmente)",
"Qt apps": "Apps Qt",
"Corner open": "Apertura por esquina",
"Reload Hyprland & Quickshell": "Recargar Hyprland y Quickshell",
". Notes for Zerochan:\n- You must enter a color\n- Set your zerochan username in `sidebar.booru.zerochan.username` config option. You [might be banned for not doing so](https://www.zerochan.net/api#:~:text=The%20request%20may%20still%20be%20completed%20successfully%20without%20this%20custom%20header%2C%20but%20your%20project%20may%20be%20banned%20for%20being%20anonymous.)!": ". Notas para Zerochan:\n- Debes ingresar un color\n- Configura tu nombre de usuario de Zerochan en la opción `sidebar.booru.zerochan.username`. ¡[Podrías ser baneado si no lo haces](https://www.zerochan.net/api#:~:text=The%20request%20may%20still%20be%20completed%20successfully%20without%20this%20custom%20header%2C%20but%20your%20project%20may%20be%20banned%20for%20being%20anonymous.)!",
"No": "No",
"Mic toggle": "Alternar micrófono",
"Snipping area": "Área de recorte",
"Waifus only | Excellent quality, limited quantity": "Solo waifus | Excelente calidad, cantidad limitada",
"Yes": "Sí",
"Restart": "Reiniciar",
"Thin": "Delgado",
"File Explorer": "Explorador de archivos",
"Usage: <tt>%1superpaste NUM_OF_ENTRIES[i]</tt>\nSupply <tt>i</tt> when you want images\nExamples:\n<tt>%1superpaste 4i</tt> for the last 4 images\n<tt>%1superpaste 7</tt> for the last 7 entries": "Uso: <tt>%1superpaste NUM_DE_ENTRADAS[i]</tt>\nAgrega <tt>i</tt> cuando quieras imágenes\nEjemplos:\n<tt>%1superpaste 4i</tt> para las últimas 4 imágenes\n<tt>%1superpaste 7</tt> para las últimas 7 entradas",
"Font roundness": "Redondez de fuente",
"Click to cycle through power profiles": "Clic para cambiar entre perfiles de energía",
"Split buttons": "Botones divididos",
"Bar & screen": "Barra y pantalla",
"Pin to Start": "Anclar al inicio",
"Used for displaying numbers": "Usada para mostrar números",
"Center clock": "Reloj centrado",
"Audio": "Audio",
"Select the language for the user interface.\n\"Auto\" will use your system's locale.": "Selecciona el idioma de la interfaz.\n\"Auto\" usará la configuración regional de tu sistema.",
"Unknown Album": "Álbum desconocido",
"Your package manager is running": "Tu gestor de paquetes está en ejecución",
"Swap": "Intercambio",
"Total token count\nInput: %1\nOutput: %2": "Total de tokens\nEntrada: %1\nSalida: %2",
"Volume limit": "Límite de volumen",
"Sign out": "Cerrar sesión",
"Tonal Spot": "Tono puntual",
"Apps": "Aplicaciones",
"Privacy Policy": "Política de privacidad",
"Media": "Multimedia",
"%1 Safe Storage": "%1 Almacenamiento seguro",
"Network": "Red",
"Inactive": "Inactivo",
"Save chat to %1": "Guardar chat en %1",
"RAM": "RAM",
"No media": "Sin multimedia",
"Invalid arguments. Must provide `command`.": "Argumentos no válidos. Se debe proporcionar `command`.",
"Bluetooth": "Bluetooth",
"Least busy": "Menos ocupado",
"When not fullscreen": "Cuando no está en pantalla completa",
"Used for general UI text": "Usada para texto general de la interfaz",
"Prefixes": "Prefijos",
"Weeb": "Weeb",
"Bluetooth devices": "Dispositivos Bluetooth",
"Anime": "Anime",
"Tray": "Bandeja",
"Top": "Arriba",
"Policies": "Políticas",
"Get the latest features and security improvements with\nthe newest feature update.\n\n%1 packages": "Obtén las últimas funciones y mejoras de seguridad con\nla actualización más reciente.\n\n%1 paquetes",
"Pressure": "Presión",
"Math": "Matemáticas",
"Enter tags, or \"%1\" for commands": "Ingresa etiquetas, o \"%1\" para comandos",
"Enable GPS based location": "Activar ubicación por GPS",
"Super key symbol": "Símbolo de la tecla Super",
"Load chat": "Cargar chat",
"Hibernate": "Hibernar",
"Config file": "Archivo de\nconfiguración",
"Stroke width": "Grosor de trazo",
"Reading font": "Fuente de lectura",
"Close all windows": "Cerrar todas las ventanas",
"Workspace": "Espacio de trabajo",
"Clock style (locked)": "Estilo de reloj (bloqueado)",
"Right": "Derecha",
"Night Light": "Luz nocturna",
"12h am/pm": "12h am/pm",
"Couldn't recognize music": "No se pudo reconocer la música",
"Fidelity": "Fidelidad",
"Settings": "Configuración",
"Hover to reveal": "Pasar el cursor para revelar",
"Polling interval (s)": "Intervalo de consulta (s)",
"Load prompt from %1": "Cargar prompt desde %1",
"Web": "Web",
"Dots": "Puntos",
"Rect": "Rectángulo",
"Be patient...": "Ten paciencia...",
"Free:": "Libre:",
"Allow NSFW content": "Permitir contenido NSFW",
"Sound effects": "Efectos de sonido",
"Language": "Idioma",
"Circle to Search": "Círculo para buscar",
"Transparency": "Transparencia",
"Networking": "Redes",
"Large language models": "Modelos de lenguaje",
"To set an API key, pass it with the %4 command\n\nTo view the key, pass \"get\" with the command<br/>\n\n### For %1:\n\n**Link**: %2\n\n%3": "Para establecer una clave API, pásala con el comando %4\n\nPara ver la clave, pasa \"get\" con el comando<br/>\n\n### Para %1:\n\n**Enlace**: %2\n\n%3",
"%1\nInternet access": "%1\nAcceso a Internet",
"Ignored if terminal theming is not enabled": "Se ignora si el tema de terminal no está activado",
"e.g. 󰘴 for Ctrl, 󰘵 for Alt, 󰘶 for Shift, etc": "p. ej. 󰘴 para Ctrl, 󰘵 para Alt, 󰘶 para Shift, etc.",
"Close (Esc)": "Cerrar (Esc)",
"Break": "Descanso",
"Require password to power off/restart": "Requerir contraseña para apagar/reiniciar",
"Generate translation with Gemini": "Generar traducción con Gemini",
"Battery": "Batería",
"at": "a las",
"Use symbols for mouse": "Usar símbolos para el ratón",
"Display modifiers and keys in multiple keycap (e.g., \"Ctrl + A\" instead of \"Ctrl A\" or \"󰘴 + A\" instead of \"󰘴 A\")": "Mostrar modificadores y teclas con varias teclas (p. ej., \"Ctrl + A\" en lugar de \"Ctrl A\" o \"󰘴 + A\" en lugar de \"󰘴 A\")",
"Long break": "Descanso largo",
"No active player": "Sin reproductor activo",
"Overlay: Crosshair": "Superposición: Mira",
"Why this is cool:\nFor non-0 values, it won't trigger when you reach the\nscreen corner along the horizontal edge, but it will when\nyou do along the vertical edge": "Por qué es útil:\nPara valores distintos de 0, no se activará al llegar a la\nesquina de la pantalla por el borde horizontal, pero sí\nal hacerlo por el borde vertical",
"Brightness and volume": "Brillo y volumen",
"Scroll to Bottom": "Desplazarse al final",
"Always show numbers": "Mostrar siempre los números",
"Brightness": "Brillo",
"Choose file": "Elegir archivo",
"Local only": "Solo local",
"Keybinds": "Atajos de teclado",
"Go to source (%1)": "Ir a la fuente (%1)",
"Do you want to allow this app to make changes to your device?": "¿Quieres permitir que esta aplicación realice cambios en tu dispositivo?",
"Disable tools": "Desactivar herramientas",
"Reboot to firmware settings": "Reiniciar a configuración de firmware",
"Draggable": "Arrastrable",
"Make sure your player has MPRIS support\nor try turning off duplicate player filtering": "Asegúrate de que tu reproductor tenga soporte MPRIS\no intenta desactivar el filtrado de reproductores duplicados",
"Balance brightness based on content": "Equilibrar el brillo según el contenido",
"GitHub": "GitHub",
"Info": "Información",
"Clear the current list of images": "Limpiar la lista actual de imágenes",
"Pinned on startup": "Anclado al inicio",
"Color picker": "Selector de color",
"Automatic": "Automático",
"City name": "Nombre de ciudad",
"e.g. 󱊫 for F1, 󱊶 for F12": "p. ej. 󱊫 para F1, 󱊶 para F12",
"Top-down": "De arriba hacia abajo",
"Font family name (e.g., Space Grotesk)": "Nombre de familia de fuente (p. ej., Space Grotesk)",
"Output": "Salida",
"Advanced": "Avanzado",
"Second precision": "Precisión de segundos",
"To Do": "Por hacer",
"Automatically hide": "Ocultar automáticamente",
"Quick": "Rápido",
"Keybind font size": "Tamaño de fuente de atajos",
"Hi there! First things first...": "¡Hola! Primero lo primero...",
"Music Recognition": "Reconocimiento de música",
"Listening...": "Escuchando...",
"Show": "Mostrar",
"Center icons": "Centrar iconos",
"Dot": "Punto",
"Incorrect password": "Contraseña incorrecta",
"Unmuted": "Sin silencio",
"On-screen keyboard": "Teclado en pantalla",
"Brightness adjustment": "Ajuste de brillo",
"Workspaces shown": "Espacios de trabajo mostrados",
"Donate": "Donar",
"Recognize text": "Reconocer texto",
"Content": "Contenido",
"Enter password": "Ingresar contraseña",
"Han chars": "Caracteres Han",
"Please unplug the charger": "Por favor desconecta el cargador",
"☕ Break: %1 minutes": "☕ Descanso: %1 minutos",
"Delete": "Eliminar",
"API key:\n\n```txt\n%1\n```": "Clave API:\n\n```txt\n%1\n```",
"Android": "Android",
"Done": "Listo",
"Registration failed. Please inspect manually with the <tt>warp-cli</tt> command": "El registro falló. Por favor inspecciona manualmente con el comando <tt>warp-cli</tt>",
"Enable blur": "Activar desenfoque",
"Wind": "Viento",
"Value scroll": "Desplazamiento de valor",
"Not visible to model": "No visible para el modelo",
"Exceeded max allowed": "Se superó el máximo permitido",
"Report a Bug": "Reportar un error",
"Speakers (%1): %2": "Altavoces (%1): %2",
"Enable if you want clocks to show seconds accurately": "Activa esto si quieres que los relojes muestren los segundos con precisión",
"Not secured": "No asegurado",
"Used:": "Usado:",
"Depends on sidebars": "Depende de las barras\nlaterales",
"Second hand": "Segundero",
"Reboot": "Reiniciar",
"Reject": "Rechazar",
"For storing API keys and other sensitive information": "Para almacenar claves API y otra información sensible",
"Not connected": "No conectado",
"Critically low battery": "Batería críticamente baja",
"Show this window on all desktops": "Mostrar esta ventana en todos los escritorios",
"Time": "Hora",
"Sliders": "Controles deslizantes",
"Enabled": "Activado",
"For desktop wallpapers | Good quality": "Para fondos de escritorio | Buena calidad",
"Left to right": "De izquierda a derecha",
"Quick toggles": "Interruptores rápidos",
"Details": "Detalles",
"Audio output | Right-click for volume mixer & device selector": "Salida de audio | Clic derecho para mezclador de volumen y selector de dispositivo",
"Use the system file picker instead\nRight-click to make this the default behavior": "Usar el selector de archivos del sistema en su lugar\nClic derecho para establecer esto como comportamiento predeterminado",
"Thought": "Pensamiento",
"Volume": "Volumen",
"Emojis": "Emojis",
"Time to full:": "Tiempo para carga completa:",
"Could be images or parts of the screen that have some containment.\nMight not always be accurate.\nThis is done with an image processing algorithm run locally and no AI is used.": "Pueden ser imágenes o partes de la pantalla con algún contenido delimitado.\nPuede no ser siempre preciso.\nEsto se realiza con un algoritmo de procesamiento de imágenes local, sin IA.",
"Perhaps what you're listening to is too niche": "Quizás lo que estás escuchando es demasiado de nicho",
"Command": "Comando",
"Wallpaper selector": "Selector de fondo de pantalla",
"Muted": "Silenciado",
"Sleep": "Suspender",
"Gives the model search capabilities (immediately)": "Proporciona al modelo capacidades de búsqueda (de inmediato)",
"Crosshair code (in Valorant's format)": "Código de mira (en formato de Valorant)",
"Used for headings and titles": "Usada para encabezados y títulos",
"Uses Gemini to categorize the wallpaper then picks a preset based on it.\nYou'll need to set Gemini API key on the left sidebar first.\nImages are downscaled for performance, but just to be safe,\ndo not select wallpapers with sensitive information.": "Usa Gemini para categorizar el fondo de pantalla y luego selecciona un preset basado en eso.\nNecesitarás establecer la clave API de Gemini en la barra lateral izquierda primero.\nLas imágenes se reducen para mejorar el rendimiento, pero por seguridad,\nno selecciones fondos con información sensible.",
"Night Light | Right-click to toggle Auto mode": "Luz nocturna | Clic derecho para alternar modo automático",
"Change password": "Cambiar contraseña",
"Unknown Title": "Título desconocido",
"Numbers": "Números",
"24h": "24h",
"No applications": "Sin aplicaciones",
"Force hover open at absolute corner": "Forzar apertura al pasar por la esquina exacta",
"of %1": "de %1",
"Code saved to file": "Código guardado en archivo",
"Content region": "Región de contenido",
"Invalid model. Supported: \n```": "Modelo no válido. Compatibles: \n```",
"Font family name": "Nombre de familia de fuente",
"Please charge!\nAutomatic suspend triggers at %1%": "¡Por favor carga el dispositivo!\nLa suspensión automática se activa al %1%",
"Manage accounts": "Administrar cuentas",
"Open editor": "Abrir editor",
"Font used for Nerd Font icons": "Fuente usada para iconos de Nerd Font",
"Commands, edit configs, search.\nTakes an extra turn to switch to search mode if that's needed": "Comandos, editar configuraciones, buscar.\nRequiere un turno extra para cambiar a modo búsqueda si es necesario",
"Record": "Grabar",
"Used for decorative/expressive text": "Usada para texto decorativo/expresivo",
"Visualize region": "Visualizar región",
"Language not listed or incomplete translations?\nYou can choose to generate translations for it with Gemini.\n1. Open the left sidebar with Super+A, set model to Gemini (if it isn't already)\n2. Type /key, hit Enter and follow the instructions\n3. Type /key YOUR_API_KEY\n4. Type the locale of your language below and press Generate": "¿Idioma no listado o traducciones incompletas?\nPuedes elegir generar traducciones con Gemini.\n1. Abre la barra lateral izquierda con Super+A, establece el modelo en Gemini (si no lo está ya)\n2. Escribe /key, presiona Enter y sigue las instrucciones\n3. Escribe /key TU_CLAVE_API\n4. Escribe el código de idioma abajo y presiona Generar",
"Saving...": "Guardando...",
"Monochrome": "Monocromático",
"Random osu! seasonal background\nImage is saved to ~/Pictures/Wallpapers": "Fondo estacional aleatorio de osu!\nLa imagen se guarda en ~/Pictures/Wallpapers",
"Polkit": "Polkit",
"Manage my account": "Administrar mi cuenta",
"Edit quick toggles": "Editar interruptores rápidos",
"Unknown function call: %1": "Llamada de función desconocida: %1",
"Clipboard": "Portapapeles",
"<b>Dims screen content</b> as needed.<br><br>Pros: Immediately responsive<br>Cons: Expensive and can hurt color accuracy<br><br><i>Uses a Hyprland screen shader</i>": "<b>Atenúa el contenido de la pantalla</b> según sea necesario.<br><br>Ventajas: Responde de inmediato<br>Desventajas: Costoso y puede afectar la precisión del color<br><br><i>Usa un shader de pantalla de Hyprland</i>",
"No new notifications": "Sin nuevas notificaciones",
"Volume mixer": "Mezclador de volumen",
"Force dark mode in terminal": "Forzar modo oscuro en la terminal",
"Save paths": "Guardar rutas",
"Copy path": "Copiar ruta",
"Anime boorus": "Boorus de anime",
"Open network portal": "Abrir portal de red",
"Quick markup (Ctrl+E)": "Marcado rápido (Ctrl+E)",
"Large images | God tier quality, no NSFW.": "Imágenes grandes | Calidad excepcional, sin NSFW.",
"Polling interval (ms)": "Intervalo de consulta (ms)",
"Model set to %1": "Modelo establecido en %1",
"Identify Music": "Identificar música",
"Circle selection": "Selección circular",
"Dark Mode": "Modo oscuro",
"Make icons pinned by default": "Anclar iconos de forma predeterminada",
"User agent (for services that require it)": "Agente de usuario (para servicios que lo requieren)",
"Use varying shapes for password characters": "Usar formas variadas para los caracteres de contraseña",
"Search, calculate or run": "Buscar, calcular o ejecutar",
"More Bluetooth settings": "Más ajustes de Bluetooth",
"Output device": "Dispositivo de salida",
"Random SFW Anime wallpaper from Konachan\nImage is saved to ~/Pictures/Wallpapers": "Fondo de anime SFW aleatorio de Konachan\nLa imagen se guarda en ~/Pictures/Wallpapers",
"Rectangle": "Rectángulo",
"Tip: right-clicking a group\nalso expands it": "Consejo: hacer clic derecho en un grupo\ntambién lo expande",
"Pin to taskbar": "Anclar a la barra de tareas",
"Show date": "Mostrar fecha",
"Battery: %1%2": "Batería: %1%2",
"Current API endpoint: %1\nSet it with %2mode PROVIDER": "Endpoint API actual: %1\nEstablécelo con %2mode PROVEEDOR",
"Columns": "Columnas",
"Recognize music | Right-click to toggle source": "Reconocer música | Clic derecho para cambiar fuente",
"Replace 󱕐 for \"Scroll ↓\", 󱕑 \"Scroll ↑\", L󰍽 \"LMB\", R󰍽 \"RMB\", 󱕒 \"Scroll ↑/↓\" and ⇞/⇟ for \"Page_↑/↓\"": "Reemplaza 󱕐 por \"Desplazar ↓\", 󱕑 \"Desplazar ↑\", L󰍽 \"Clic izq.\", R󰍽 \"Clic der.\", 󱕒 \"Desplazar ↑/↓\" y ⇞/⇟ por \"Pág. ↑/↓\"",
"Choose model": "Elegir modelo",
"Approve": "Aprobar",
"Configuration": "Configuración",
"Hit \"/\" to search": "Presiona \"/\" para buscar",
"Regenerate": "Regenerar",
"Move right": "Mover a la derecha",
"Image source": "Fuente de imagen",
"Dock": "Dock",
"Open recordings folder": "Abrir carpeta de grabaciones",
"Pin": "Anclar",
"Click to mute": "Clic para silenciar",
"Search for apps": "Buscar aplicaciones",
"Connection failed. Please inspect manually with the <tt>warp-cli</tt> command": "La conexión falló. Por favor inspecciona manualmente con el comando <tt>warp-cli</tt>",
"Show only when locked": "Mostrar solo cuando está bloqueado",
"Sides": "Lados",
"Edit directory": "Editar directorio",
"You can also manually edit cheatsheet.superKey": "También puedes editar manualmente cheatsheet.superKey",
"Color generation": "Generación de color",
"Unpin": "Desanclar",
"Font weight": "Peso de fuente",
"Reset": "Restablecer",
"Math result": "Resultado matemático",
"Enjoy! You can reopen the welcome app any time with <tt>Super+Shift+Alt+/</tt>. To open the settings app, hit <tt>Super+I</tt>": "¡Disfruta! Puedes volver a abrir la aplicación de bienvenida en cualquier momento con <tt>Super+Shift+Alt+/</tt>. Para abrir la configuración, presiona <tt>Super+I</tt>",
"Notifications": "Notificaciones",
"Save to Downloads": "Guardar en Descargas",
"Command-line-invoked Action": "Acción invocada por línea de comandos",
"Arrow keys to navigate, Enter to select\nEsc or click anywhere to cancel": "Teclas de flecha para navegar, Enter para seleccionar\nEsc o clic en cualquier lugar para cancelar",
"Paired": "Vinculado",
"Game mode": "Modo juego",
"Emoji": "Emoji",
"Health:": "Salud:",
"Anti-flashbang (experimental)": "Anti-destello (experimental)",
"Turn on from sunset to sunrise": "Activar del atardecer al amanecer",
"Close": "Cerrar",
"Workspaces": "Espacios de trabajo",
"Record region": "Grabar región",
"Shell & utilities theming must also be enabled": "El tema de shell y utilidades también debe estar activado",
"Superpaste": "Superpegar",
"You'll need to enter your Gemini API key first.\nType /key on the sidebar for instructions.": "Primero necesitas ingresar tu clave API de Gemini.\nEscribe /key en la barra lateral para ver las instrucciones.",
"Enable update checks": "Activar verificación de actualizaciones",
"Select Language": "Seleccionar idioma",
"Locale code, e.g. fr_FR, de_DE, zh_CN...": "Código de idioma, p. ej. fr_FR, de_DE, zh_CN...",
"Desktop %1": "Escritorio %1",
"Keep awake": "Mantener activo",
"Hollow": "Hueco",
"Group style": "Estilo de grupo",
"It may take a few seconds to update": "Puede tardar unos segundos en actualizarse",
"Unknown command:": "Comando desconocido:",
"Action": "Acción",
"Set temperature (randomness) of the model. Values range between 0 to 2 for Gemini, 0 to 1 for other models. Default is 0.5.": "Establece la temperatura (aleatoriedad) del modelo. Los valores van de 0 a 2 para Gemini, de 0 a 1 para otros modelos. El valor predeterminado es 0.5.",
"Style: Blurred": "Estilo: Difuminado",
"Parallax": "Desplazamiento",
"Bubble": "Burbuja",
"Saved to %1": "Guardado en %1",
"Current tool: %1\nSet it with %2tool TOOL": "Herramienta actual: %1\nEstablécela con %2tool HERRAMIENTA",
"The popular one | Best quantity, but quality can vary wildly": "El popular | Mayor cantidad, pero la calidad puede variar mucho",
"Sidebars": "Barras laterales",
"Description font size": "Tamaño de fuente de descripción",
"Close window": "Cerrar ventana",
"Calendar": "Calendario",
"%1 mins": "%1 min",
"Automatically suspends the system when battery is low": "Suspende automáticamente el sistema cuando la batería está baja",
"Enable": "Activar",
"Show aim lines": "Mostrar líneas de mira",
"Overview": "Vista general",
"Enable opening zoom animation": "Activar animación de zoom al abrir",
"Copy code": "Copiar código",
"Path copied": "Ruta copiada",
"Audio output": "Salida de audio",
"Open file link": "Abrir enlace de archivo",
"Tooltips": "Información emergente",
"Move left": "Mover a la izquierda",
"Sound output": "Salida de sonido",
"Windows": "Ventanas",
"Fahrenheit unit": "Unidad Fahrenheit",
"Night Light | Right-click to configure": "Luz nocturna | Clic derecho para configurar",
"Set API key": "Establecer clave API",
"Markdown test": "Prueba de Markdown",
"Pills": "Píldoras",
"Font family name (e.g., Google Sans Flex)": "Nombre de familia de fuente (p. ej., Google Sans Flex)",
"illogical-impulse": "illogical-impulse",
"... and %1 more": "... y %1 más",
"Shell & utilities": "Shell y utilidades",
"Provider set to": "Proveedor establecido en",
"Main font": "Fuente principal",
"Dotfiles": "Dotfiles",
"Current model: %1\nSet it with %2model MODEL": "Modelo actual: %1\nEstablécelo con %2model MODELO",
"Nerd font icons": "Iconos de Nerd Font",
"Style & wallpaper": "Estilo y fondo de pantalla",
"Scroll to change brightness": "Desplazar para cambiar el brillo",
"Input": "Entrada",
"Intensity": "Intensidad",
"🔴 Focus: %1 minutes": "🔴 Enfoque: %1 minutos",
"Lock screen": "Pantalla de bloqueo",
"Password": "Contraseña",
"with vertical offset": "con desplazamiento vertical",
"Fill": "Relleno",
"Generating...\nDon't close this window!": "Generando...\n¡No cierres esta ventana!",
"Online | %1's model | Delivers fast, responsive and well-formatted answers. Disadvantages: not very eager to do stuff; might make up unknown function calls": "En línea | Modelo de %1 | Proporciona respuestas rápidas, ágiles y bien formateadas. Desventajas: no muy dispuesto a hacer cosas; puede inventar llamadas de función desconocidas",
"Feels like %1": "Sensación térmica %1",
"Welcome app": "App de bienvenida",
"Start": "Iniciar",
"Digital clock settings": "Configuración del reloj digital",
"Expressive": "Expresivo",
"Auto,": "Auto,",
"Task View": "Vista de tareas",
"Bottom-up": "De abajo hacia arriba",
"Type /key to get started with online models\nCtrl+O to expand sidebar\nCtrl+P to pin sidebar\nCtrl+D to detach sidebar": "Escribe /key para comenzar con modelos en línea\nCtrl+O para expandir la barra lateral\nCtrl+P para anclar la barra lateral\nCtrl+D para desanclar la barra lateral",
"Wallpaper safety enforced": "Seguridad de fondo de pantalla aplicada",
"Automatic suspend": "Suspensión automática",
"Music Recognized": "Música reconocida",
"Cookie": "Cookie",
"UV Index": "Índice UV",
"API key is set\nChange with /key YOUR_API_KEY": "Clave API establecida\nCámbiala con /key TU_CLAVE_API",
"Show next time": "Mostrar la próxima vez",
"Most busy": "Más ocupado",
"Finished tasks will go here": "Las tareas completadas aparecerán aquí",
"EasyEffects": "EasyEffects",
"Issues": "Problemas",
"Load:": "Carga:",
"Hug": "Abrazo",
"(Plugged in)": "(Conectado)",
"Discussions": "Discusiones",
"Enter text to translate...": "Ingresa texto para traducir...",
"Low battery": "Batería baja",
"Positioning": "Posicionamiento",
"Allows you to open sidebars by clicking or hovering screen corners regardless of bar position": "Te permite abrir las barras laterales haciendo clic o pasando el cursor por las esquinas de la pantalla independientemente de la posición de la barra",
"Resources": "Recursos",
"Load chat from %1": "Cargar chat desde %1",
"Clear all": "Limpiar todo",
"OK": "Aceptar",
"Tip: Close a window with Super+Q": "Consejo: Cierra una ventana con Super+Q",
"Clean stuff | Excellent quality, no NSFW": "Contenido limpio | Excelente calidad, sin NSFW",
"Save": "Guardar",
"Productivity": "Productividad",
"Disable NSFW content": "Desactivar contenido NSFW",
"Locked": "Bloqueado",
"Nothing here!": "¡Nada aquí!",
"Temperature: %1": "Temperatura: %1",
"Hour marks": "Marcas de hora",
"Web search": "Búsqueda web",
"No pending tasks": "Sin tareas pendientes",
"Circle": "Círculo",
"API key set for %1": "Clave API establecida para %1",
"Unknown device": "Dispositivo desconocido",
"Scroll to change volume": "Desplazar para cambiar el volumen",
"Generate\nTypically takes 2 minutes": "Generar\nGeneralmente tarda 2 minutos",
"Allow NSFW": "Permitir NSFW",
"Stopwatch": "Cronómetro",
"Hint target regions": "Resaltar regiones objetivo",
"Text extractor": "Extractor de texto",
"Open the shell config file\nAlternatively right-click to copy path": "Abrir el archivo de configuración del shell\nAlternativamente, clic derecho para copiar la ruta",
"No API key set for %1": "No hay clave API establecida para %1",
"Critical warning": "Advertencia crítica",
"Animate time change": "Animar cambio de hora",
"Screen snip": "Captura de pantalla",
"CPU": "CPU",
"Nothing": "Nada",
"Focus": "Enfoque",
"Run": "Ejecutar",
"Temperature must be between 0 and 2": "La temperatura debe estar entre 0 y 2",
"Could be better if you make a ton of typos,\nbut results can be weird and might not work with acronyms\n(e.g. \"GIMP\" might not give you the paint program)": "Puede funcionar mejor si cometes muchos errores tipográficos,\npero los resultados pueden ser extraños y puede que no funcione con acrónimos\n(p. ej., \"GIMP\" puede que no te dé el programa de edición)",
"Documentation": "Documentación",
"Screenshot Path (leave empty to just copy)": "Ruta de captura de pantalla (deja vacío para solo copiar)",
"Help & Support": "Ayuda y soporte",
"All-rounder | Good quality, decent quantity": "Versátil | Buena calidad, cantidad decente",
"On": "Activado",
"Earbang protection": "Protección contra destellos de audio",
"Rainbow": "Arcoíris",
"Download": "Descargar",
"Cloudflare WARP": "Cloudflare WARP",
"Audio input | Right-click for volume mixer & device selector": "Entrada de audio | Clic derecho para mezclador de volumen y selector de dispositivo",
"Random: Konachan": "Aleatorio: Konachan",
"Usage: %1tool TOOL_NAME": "Uso: %1tool NOMBRE_HERRAMIENTA",
"Use symbols for function keys": "Usar símbolos para teclas de función",
"Lap": "Vuelta",
"Active": "Activo",
"Local Ollama model | %1": "Modelo local de Ollama | %1",
"Shell command": "Comando de shell",
"Hide clipboard images copied from sussy sources": "Ocultar imágenes del portapapeles copiadas de fuentes sospechosas",
"Creativity": "Creatividad",
"Select language": "Seleccionar idioma",
"Usage": "Uso",
"Show \"Locked\" text": "Mostrar texto \"Bloqueado\"",
"Adjust the color temperature": "Ajustar la temperatura de color",
"Move to front": "Mover al frente",
"Pick a wallpaper": "Elegir un fondo de pantalla",
"Logout": "Cerrar sesión",
"Unknown": "Desconocido",
"If you want to somehow use fingerprint unlock...": "Si quieres usar desbloqueo por huella digital de alguna manera...",
"Precipitation": "Precipitación",
"Change any time later with /dark, /light, /wallpaper in the launcher\nIf the shell's colors aren't changing:\n 1. Open the right sidebar with Super+N\n 2. Click \"Reload Hyprland & Quickshell\" in the top-right corner": "Cámbialo cuando quieras con /dark, /light, /wallpaper en el lanzador\nSi los colores del shell no cambian:\n 1. Abre la barra lateral derecha con Super+N\n 2. Haz clic en \"Recargar Hyprland y Quickshell\" en la esquina superior derecha",
"Digital": "Digital",
"Full": "Completo",
"Microphone": "Micrófono",
"Clock style": "Estilo de reloj",
"Used for code and terminal": "Usada para código y terminal",
"Prevents abrupt increments and restricts volume limit": "Previene incrementos abruptos y restringe el límite de volumen",
"Download complete": "Descarga completa",
"Connect to Wi-Fi": "Conectar a Wi-Fi",
"Use adaptive alignment": "Usar alineación adaptativa",
"System prompt": "Prompt de sistema",
"Enjoy your empty sidebar...": "Disfruta tu barra lateral vacía...",
"Fruit Salad": "Ensalada de frutas",
"Overlay: Floating Image": "Superposición: Imagen flotante",
"Auto styling with Gemini": "Estilo automático con Gemini",
"Anti-flashbang": "Anti-destello",
"Cloudflare WARP (1.1.1.1)": "Cloudflare WARP (1.1.1.1)",
"Font family name (e.g., Readex Pro)": "Nombre de familia de fuente (p. ej., Readex Pro)",
"Pause": "Pausar",
"Interface": "Interfaz",
"Number style": "Estilo de número",
"Set the current API provider": "Establecer el proveedor de API actual",
"Remember that on most devices one can always hold the power button to force shutdown\nThis only makes it a tiny bit harder for accidents to happen": "Recuerda que en la mayoría de dispositivos siempre puedes mantener presionado el botón de encendido para forzar el apagado\nEsto solo hace que sea un poco más difícil que ocurran accidentes",
"Weather Service": "Servicio meteorológico",
"Vertical": "Vertical",
"Write something here...\nUse '-' to create copyable bullet points, like this:\n\nSheep fricker\n- 4x Slab\n- 1x Boat\n- 4x Redstone Dust\n- 1x Sticky Piston\n- 1x End Rod\n- 4x Redstone Repeater\n- 1x Redstone Torch\n- 1x Sheep": "Escribe algo aquí...\nUsa '-' para crear viñetas copiables, así:\n\nOveja traviesa\n- 4x Losa\n- 1x Bote\n- 4x Polvo de redstone\n- 1x Pistón pegajoso\n- 1x Varilla del End\n- 4x Repetidor de redstone\n- 1x Antorcha de redstone\n- 1x Oveja",
"Edit": "Editar",
"Add task": "Agregar tarea",
"Depends on workspace": "Depende del espacio\nde trabajo",
"Use old sine wave cookie implementation": "Usar implementación antigua de cookie en onda sinusoidal",
"Darken screen": "Oscurecer pantalla",
"Border": "Borde",
"This is usually safe and needed for your browser and AI sidebar anyway\nMostly useful for those who use lock on startup instead of a display manager that does it (GDM, SDDM, etc.)": "Esto generalmente es seguro y necesario para tu navegador y la barra lateral de IA de todas formas\nPrincipalmente útil para quienes usan bloqueo al inicio en lugar de un gestor de pantalla que lo hace (GDM, SDDM, etc.)",
"Shell conflicts killer": "Eliminador de conflictos del shell",
"End session": "Terminar sesión",
"Best match": "Mejor coincidencia",
"Online | Google's model\nPro-level intelligence at the speed and pricing of Flash.": "En línea | Modelo de Google\nInteligencia de nivel Pro a la velocidad y precio de Flash.",
"Font family": "Familia de fuente",
"The hentai one | Great quantity, a lot of NSFW, quality varies wildly": "El de hentai | Gran cantidad, mucho NSFW, la calidad varía mucho",
"Notes": "Notas",
"Actions": "Acciones",
"Task description": "Descripción de tarea",
"Eye protection": "Protección ocular",
"Image search": "Búsqueda de imágenes",
"Saved": "Guardado",
"Neutral": "Neutro",
"Conflicts with the shell's notification implementation": "Conflicto con la implementación de notificaciones del shell",
"Resume": "Reanudar",
"Low warning": "Advertencia baja",
"Task Manager": "Administrador de tareas",
"Aligns the date and quote to left, center or right depending on its position on the screen.": "Alinea la fecha y la cita a la izquierda, al centro o a la derecha según su posición en la pantalla.",
"Utilities & Tools": "Utilidades y herramientas",
"Snip": "Recortar",
"Time to empty:": "Tiempo para agotar:",
"%1 | Right-click to configure": "%1 | Clic derecho para configurar",
"Consider plugging in your device": "Considera conectar tu dispositivo",
"%1 does not require an API key": "%1 no requiere una clave API",
"Cancel wallpaper selection": "Cancelar selección de fondo de pantalla",
"See fewer": "Ver menos",
"Click to toggle light/dark mode\n(applied when wallpaper is chosen)": "Clic para alternar modo claro/oscuro\n(se aplica al elegir el fondo de pantalla)",
"LMB to enable/disable\nRMB to toggle size\nScroll to swap position": "Clic izq. para activar/desactivar\nClic der. para alternar tamaño\nDesplazar para cambiar posición",
"Window": "Ventana",
"Cancel": "Cancelar",
"Unknown Artist": "Artista desconocido",
"Press Super+G to open the overlay and pin the crosshair": "Presiona Super+G para abrir la superposición y anclar la mira",
"Set the system prompt for the model.": "Establece el prompt de sistema para el modelo.",
"Format": "Formato",
"Unpin from taskbar": "Desanclar de la barra de tareas",
"Charging:": "Cargando:",
"System updates (Arch only)": "Actualizaciones del sistema (solo Arch)",
"Line": "Línea",
"Quote": "Cita",
"Interface Language": "Idioma de la interfaz",
"Terminal: Harmonize threshold": "Terminal: Umbral de armonización",
"System uptime:": "Tiempo de actividad del sistema:",
"Enable now": "Activar ahora",
"Virtual Keyboard": "Teclado virtual",
"Click to show": "Clic para mostrar",
"When enabled keeps the content of the right sidebar loaded to reduce the delay when opening,\nat the cost of around 15MB of consistent RAM usage. Delay significance depends on your system's performance.\nUsing a custom kernel like linux-cachyos might help": "Cuando está activado, mantiene el contenido de la barra lateral derecha cargado para reducir el retraso al abrir,\na costa de un uso constante de RAM de aproximadamente 15 MB. La importancia del retraso depende del rendimiento de tu sistema.\nUsar un kernel personalizado como linux-cachyos podría ayudar",
"Secured": "Asegurado",
"**Pricing**: free. Data used for training.\n\n**Instructions**: Log into Google account, allow AI Studio to create Google Cloud project or whatever it asks, go back and click Get API key": "**Precio**: gratis. Los datos se usan para entrenamiento.\n\n**Instrucciones**: Inicia sesión en tu cuenta de Google, permite que AI Studio cree un proyecto de Google Cloud o lo que solicite, regresa y haz clic en Obtener clave API",
"Forget": "Olvidar",
"Loaded the following system prompt\n\n---\n\n%1": "Se cargó el siguiente prompt de sistema\n\n---\n\n%1",
"Attach a file. Only works with Gemini.": "Adjuntar un archivo. Solo funciona con Gemini.",
"Temperature set to %1": "Temperatura establecida en %1",
"Desktop": "Escritorio",
"Preferred wallpaper zoom (%)": "Zoom preferido del fondo de pantalla (%)",
"Set FPS limit": "Establecer límite de FPS",
"Line-separated": "Separado por líneas",
"Also unlock keyring": "También desbloquear el llavero",
"Pick random from this folder": "Elegir aleatoriamente de esta carpeta",
"Font width": "Ancho de fuente",
"Enter a valid number": "Ingresa un número válido",
"Medium": "Mediano",
"Search with Google Lens": "Buscar con Google Lens",
"Wi-Fi": "Wi-Fi",
"Padding": "Relleno interior",
"Layers": "Capas",
"Float": "Flotante",
"Hover to trigger": "Pasar el cursor para activar",
"Other": "Otro",
"Focusing": "Enfocando",
"Session": "Sesión",
"Timeout duration (if not defined by notification) (ms)": "Duración del tiempo de espera (si no está definido por la notificación) (ms)",
"Local account": "Cuenta local",
"Invalid arguments. Must provide `key` and `value`.": "Argumentos no válidos. Se deben proporcionar `key` y `value`.",
"Closet": "De clóset",
"Used for reading large blocks of text": "Usada para leer bloques grandes de texto",
"Polling interval (m)": "Intervalo de consulta (m)",
"Kill conflicting programs?": "¿Terminar programas en conflicto?",
"Light": "Claro",
"Translator": "Traductor",
"Visibility": "Visibilidad",
"Copy region (LMB) or annotate (RMB)": "Copiar región (clic izq.) o anotar (clic der.)",
"Performance Profile toggle": "Alternar perfil de rendimiento",
"Distro": "Distro",
"Add": "Agregar",
"Timeout (ms)": "Tiempo de espera (ms)",
"That didn't work. Tips:\n- Check your tags and NSFW settings\n- If you don't have a tag in mind, type a page number": "Eso no funcionó. Consejos:\n- Revisa tus etiquetas y configuración NSFW\n- Si no tienes una etiqueta en mente, escribe un número de página",
"Temperature\nChange with /temp VALUE": "Temperatura\nCámbiala con /temp VALOR",
"Digits in the middle": "Dígitos en el centro",
"Bold": "Negrita",
"Pomodoro": "Pomodoro",
"AI": "IA",
"Content adjustment": "Ajuste de contenido",
"No API key\nSet it with /key YOUR_API_KEY": "Sin clave API\nEstablécela con /key TU_CLAVE_API",
"Hide sussy/anime wallpapers": "Ocultar fondos de pantalla sospechosos/anime",
"Always": "Siempre",
"Overlay: General": "Superposición: General",
"Background": "Fondo",
"Usage: %1save CHAT_NAME": "Uso: %1save NOMBRE_CHAT",
"Terminal": "Terminal",
"Left": "Izquierda",
"Shutdown": "Apagado",
"or": "o",
"Discharging:": "Descargando:",
"🌿 Long break: %1 minutes": "🌿 Descanso largo: %1 minutos",
"Use Levenshtein distance-based algorithm instead of fuzzy": "Usar algoritmo basado en distancia de Levenshtein en lugar de búsqueda difusa",
"Auto (System)": "Auto (Sistema)",
"Use system file picker": "Usar selector de archivos del sistema",
"Up %1": "Encendido %1",
"%1 characters": "%1 caracteres",
"Invalid API provider. Supported: \n-": "Proveedor de API no válido. Compatibles: \n-",
"Humidity": "Humedad",
"Use Hyprlock (instead of Quickshell)": "Usar Hyprlock (en lugar de Quickshell)",
"Search wallpapers": "Buscar fondos de pantalla",
"Total duration timeout (s)": "Tiempo de espera total (s)",
"Check interval (mins)": "Intervalo de verificación (min)",
"Rectangular selection": "Selección rectangular",
"%1 • %2 tasks": "%1 • %2 tareas",
"Terminal: Harmony (%)": "Terminal: Armonía (%)",
"Title font": "Fuente de título",
"Fully charged": "Completamente cargado",
"+%1 notifications": "+%1 notificaciones",
"**Instructions**: Log into Mistral account, go to Keys on the sidebar, click Create new key": "**Instrucciones**: Inicia sesión en tu cuenta de Mistral, ve a Claves en la barra lateral, haz clic en Crear nueva clave",
"Unknown Application": "Aplicación desconocida",
"Power Profile": "Perfil de energía",
"Place at bottom": "Colocar en la parte inferior",
"Extra wallpaper zoom (%)": "Zoom adicional del fondo de pantalla (%)",
"Unfinished": "Sin terminar",
"Silent": "Silencioso",
"On-screen display": "Visualización en pantalla",
"Clear chat history": "Limpiar historial de chat",
"%1 notifications": "%1 notificaciones",
"EasyEffects | Right-click to configure": "EasyEffects | Clic derecho para configurar",
"Cookie clock settings": "Configuración del reloj Cookie",
"Widget: Clock": "Widget: Reloj",
"Keep system awake": "Mantener el sistema activo",
"Right to left": "De derecha a izquierda",
"Elements": "Elementos",
"Off": "Desactivado",
"Region selector (screen snipping/Google Lens)": "Selector de región (recorte de pantalla/Google Lens)",
"Search": "Buscar",
"Max allowed increase": "Incremento máximo\npermitido",
"Total:": "Total:",
"12h AM/PM": "12h AM/PM",
"Thinking": "Pensando",
"Random: osu! seasonal": "Aleatorio: estacional de osu!",
"Constantly rotate": "Rotar constantemente",
"Scale (%)": "Escala (%)",
"Audio input": "Entrada de audio",
"Conflicts with the shell's system tray implementation": "Conflicto con la implementación de la bandeja del sistema del shell",
"General": "General",
"Place the corners to trigger at the bottom": "Colocar las esquinas de activación en la parte inferior",
"Google Lens": "Google Lens",
"App": "Aplicación",
"System sound": "Sonido del sistema",
"<i>No further instruction provided</i>": "<i>No se proporcionaron instrucciones adicionales</i>",
"Enable translator": "Activar traductor",
"Auto": "Auto",
"Switched to search mode. Continue with the user's request.": "Cambiado a modo búsqueda. Continúa con la solicitud del usuario.",
"Screen round corner": "Esquina redondeada de pantalla",
"Terminal: Foreground boost (%)": "Terminal: Impulso de primer plano (%)",
"Show app icons": "Mostrar iconos de aplicaciones",
"Full warning": "Advertencia de carga completa",
"More volume settings": "Más ajustes de volumen",
"Region height": "Altura de región",
"Intelligence": "Inteligencia",
"Unread indicator: show count": "Indicador de no leídos: mostrar conteo",
"Last refresh: %1": "Última actualización: %1",
"Launch on startup": "Iniciar al arranque",
"Keyboard toggle": "Alternar teclado",
"Bar position": "Posición de la barra",
"Back": "Atrás",
"Pick wallpaper image on your system": "Elegir imagen de fondo de pantalla de tu sistema",
"Get the next page of results": "Obtener la siguiente página de resultados",
"illogical-impulse Welcome": "Bienvenida de illogical-impulse",
"Message the model... \"%1\" for commands": "Envía un mensaje al modelo... \"%1\" para comandos",
"Make sure you have songrec installed": "Asegúrate de tener songrec instalado",
"Commands": "Comandos",
"Pinned": "Anclado",
"Tint icons": "Colorear iconos",
"Battery full": "Batería llena",
"To Do:": "Por hacer:",
"Tint app icons": "Colorear iconos de aplicaciones",
"Weather": "Clima",
"Usage: %1load CHAT_NAME": "Uso: %1load NOMBRE_CHAT",
"Font size": "Tamaño de fuente",
"System": "Sistema",
"More Internet settings": "Más ajustes de Internet",
"Utility buttons": "Botones de utilidad"
}
@@ -330,6 +330,10 @@
"Connect to Wi-Fi": "Подкл. к Wi-Fi",
"... and %1 more": "... и ещё %1",
"Cookie clock settings": "Настройки «Cookie»-часов",
"Looks a bit softer and more consistent with different number of sides,\nbut has less impressive morphing": "Выглядит мягче и уместнее с разным количеством углов,\nно сжатие может выглядить менее впечатляюще",
"Makes the clock always rotate. This is extremely expensive\n(expect 50% usage on Intel UHD Graphics) and thus impractical.": "Часы будут постоянно вращаться. Это крайне ресурсозатратно\n(примерно 50% использования Intel UHD Graphics) и фактически бесполезно.",
"Can only be turned on using the 'Dots' or 'Full' dial style for aesthetic reasons": "Может быть активировано только в режимах 'С точками' и 'Полностью залитый' по эстетическим причинам",
"Can't be turned on when using 'Numbers' dial style for aesthetic reasons": "Не может быть включено, когда используется стиль 'С числами' по эстетическим причинам",
"Brightness and volume": "Яркость и громкость",
"Choose file": "Выбор обоев",
"Invalid model. Supported: \n```": "Неверная модель. Поддерживаемые: \n```",
+42
View File
@@ -0,0 +1,42 @@
%global source_date_epoch_from_changelog 0
%global tag 1.0.4
%global commits 1054
%global commit 91b6b78e408a8b1c0b7146c9034a03156c082da2
%global shortcommit %(c=%{commit}; echo ${c:0:7})
Name: cpptrace
Version: 1.0.4
Release: 1%{?dist}
Summary: Simple, portable, and self-contained stacktrace library for C++11 and newer
License: MIT
URL: https://github.com/jeremy-rifkin/cpptrace
Source0: %{url}/archive/%{commit}/cpptrace-%{shortcommit}.tar.gz
BuildRequires: cmake
BuildRequires: gcc-c++
BuildRequires: make
BuildRequires: ninja-build
%description
C++ lightweight logging library used by Quickshell.
%prep
%autosetup -n cpptrace-%{commit} -p1
%build
mkdir -p build
cd build
cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local -DCPPTRACE_UNWIND_WITH_LIBUNWIND=true
cmake --build .
%install
cd build
DESTDIR=%{buildroot} cmake --install .
%files
%{_prefix}/local/include/*
%{_prefix}/local/lib64/*
%license LICENSE
%doc README.md
+3 -3
View File
@@ -2,10 +2,10 @@
%bcond_with asan
%global commit db1777c20b936a86528c1095cbcb1ebd92801402
%global commit 7511545ee20664e3b8b8d3322c0ffe7567c56f7a
%global shortcommit %(c=%{commit}; echo ${c:0:7})
%global commits 699
%global snapdate 20251030
%global commits 770
%global snapdate 20260327
%global tag 0.2.1
Name: quickshell-git
+1
View File
@@ -149,6 +149,7 @@ packages = [
"libdrm",
"breakpad",
"kf6-kirigami",
"libunwind-devel",
# NOTE: Below are custom dependencies of illogical-impulse
"qt6-qt5compat",
"qt6-qtimageformats",
+8 -2
View File
@@ -5,6 +5,7 @@
# -------------------------
user_config="${REPO_ROOT}/sdata/dist-fedora/user_data.yaml"
rpmbuildroot="${REPO_ROOT}/cache/rpmbuild"
rpm_specs="${REPO_ROOT}/sdata/dist-fedora/SPECS"
deps_data_file="${REPO_ROOT}/sdata/dist-fedora/feddeps.toml"
# -------------------------
@@ -31,8 +32,13 @@ function install_RPMS() {
x cp -r "${REPO_ROOT}/sdata/dist-fedora/SPECS" "$rpmbuildroot/"
x cd $rpmbuildroot/SPECS
mapfile -t -d '' local_specs < <(find "$rpmbuildroot/SPECS" -maxdepth 1 -type f -name "*.spec" -print0)
# we need cpptrace BEFORE quickshell-git
local_specs=(
"$rpm_specs/cpptrace.spec"
"$rpm_specs/quickshell-git.spec"
"$rpm_specs/hyprland-qt-support.spec"
)
for spec_file in ${local_specs[@]}; do
# Download sources
x spectool -g -C "$rpmbuildroot/SOURCES" "$spec_file"
@@ -18,7 +18,7 @@ RDEPEND="
gui-apps/hypridle
gui-apps/hyprlock
gui-apps/hyprpicker
app-misc/songrec
media-sound/songrec
app-i18n/translate-shell
gui-apps/wlogout
sci-libs/libqalculate
-3
View File
@@ -19,6 +19,3 @@ import_ebuild "${FT_DIR}" "media-fonts" "rubik-vf"
import_ebuild "${FT_DIR}" "media-fonts" "space-grotesk"
import_ebuild "${FT_DIR}" "kde-plasma" "breeze-plus"
import_ebuild "${FT_DIR}" "x11-themes" "darkly"
############### WIDGETS
import_ebuild "${WIDGETS_DIR}" "app-misc" "songrec"
+1 -2
View File
@@ -28,7 +28,6 @@ gui-libs/hyprcursor
gui-apps/wf-recorder
gui-apps/wtype
gui-apps/fuzzel
gui-apps/quickshell **
gui-apps/wlogout
dev-cpp/sdbus-c++
dev-libs/hyprland-protocols
@@ -52,7 +51,7 @@ media-fonts/space-grotesk
media-fonts/material-symbols-variable **
media-fonts/readex-pro
media-fonts/rubik-vf
app-misc/songrec
media-sound/songrec
dev-cpp/glaze
dev-cpp/cpptrace
dev-libs/libdwarf
@@ -1,48 +0,0 @@
# Copyright 2025 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
EAPI=8
DESCRIPTION="Illogicall Impulse Widget Dependencies"
HOMEPAGE=""
SRC_URI="https://github.com/marin-m/SongRec/archive/${PV}.tar.gz -> ${P}-SongRec.tar.gz"
LICENSE="GPL-2"
SLOT="0"
KEYWORDS="~amd64 ~arm64 ~x86"
# need for cargo fetch, idk how to get around it if possible
RESTRICT="strip network-sandbox"
DEPEND=""
RDEPEND=""
S="${WORKDIR}/SongRec-${PV}"
src_prepare() {
default
export CARGO_HOME="${WORKDIR}/cargo"
cargo fetch --locked --target "$(rustc -vV | sed -n 's/host: //p')"
}
src_compile() {
export CARGO_HOME="${WORKDIR}/cargo"
cargo build --release --frozen --offline
}
src_install() {
dobin target/release/songrec
insinto /usr/share/applications
doins packaging/rootfs/usr/share/applications/com.github.marinm.songrec.desktop
insinto /usr/share/icons/hicolor/scalable/apps
doins packaging/rootfs/usr/share/icons/hicolor/scalable/apps/com.github.marinm.songrec.svg
insinto /usr/share/metainfo
doins packaging/rootfs/usr/share/metainfo/com.github.marinm.songrec.metainfo.xml
insinto /usr/share/songrec/translations
doins -r translations/*
dodoc README.md
}