Make flake self-contained - consolidate installer-replication

BREAKING CHANGE: Remove external dots-hyprland dependency

- Imported all essential configs from dots-hyprland/installer-replication
- Added complete configs/ directory with:
  - hypr/ - Hyprland configuration
  - quickshell/ - Quickshell widgets and config
  - applications/ - Application configurations
  - scripts/ - Utility scripts
  - matugen/ - Material You theming
- Updated flake.nix to use local ./configs instead of external repo
- Simplified update-flake script (removed external repo management)
- Updated README to reflect self-contained architecture
- All builds pass with local configurations

Benefits:
- No external repository dependencies
- Faster builds (no network dependencies)
- Version controlled configs in single repo
- Easier maintenance and development
- Complete installer replication in one place
This commit is contained in:
Celes Renata
2025-08-08 22:26:47 -07:00
parent 22b65891ac
commit ac6d3adeb9
710 changed files with 81319 additions and 115 deletions
@@ -0,0 +1,149 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
import Quickshell.Widgets
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
ContentPage {
forceWidth: true
ContentSection {
title: Translation.tr("Distro")
RowLayout {
Layout.alignment: Qt.AlignHCenter
spacing: 20
Layout.topMargin: 10
Layout.bottomMargin: 10
IconImage {
implicitSize: 80
source: Quickshell.iconPath(SystemInfo.logo)
}
ColumnLayout {
Layout.alignment: Qt.AlignVCenter
// spacing: 10
StyledText {
text: SystemInfo.distroName
font.pixelSize: Appearance.font.pixelSize.title
}
StyledText {
font.pixelSize: Appearance.font.pixelSize.normal
text: SystemInfo.homeUrl
textFormat: Text.MarkdownText
onLinkActivated: (link) => {
Qt.openUrlExternally(link)
}
PointingHandLinkHover {}
}
}
}
Flow {
Layout.fillWidth: true
spacing: 5
RippleButtonWithIcon {
materialIcon: "auto_stories"
mainText: Translation.tr("Documentation")
onClicked: {
Qt.openUrlExternally(SystemInfo.documentationUrl)
}
}
RippleButtonWithIcon {
materialIcon: "support"
mainText: Translation.tr("Help & Support")
onClicked: {
Qt.openUrlExternally(SystemInfo.supportUrl)
}
}
RippleButtonWithIcon {
materialIcon: "bug_report"
mainText: Translation.tr("Report a Bug")
onClicked: {
Qt.openUrlExternally(SystemInfo.bugReportUrl)
}
}
RippleButtonWithIcon {
materialIcon: "policy"
materialIconFill: false
mainText: Translation.tr("Privacy Policy")
onClicked: {
Qt.openUrlExternally(SystemInfo.privacyPolicyUrl)
}
}
}
}
ContentSection {
title: Translation.tr("Dotfiles")
RowLayout {
Layout.alignment: Qt.AlignHCenter
spacing: 20
Layout.topMargin: 10
Layout.bottomMargin: 10
IconImage {
implicitSize: 80
source: Quickshell.iconPath("illogical-impulse")
}
ColumnLayout {
Layout.alignment: Qt.AlignVCenter
// spacing: 10
StyledText {
text: Translation.tr("illogical-impulse")
font.pixelSize: Appearance.font.pixelSize.title
}
StyledText {
text: "https://github.com/end-4/dots-hyprland"
font.pixelSize: Appearance.font.pixelSize.normal
textFormat: Text.MarkdownText
onLinkActivated: (link) => {
Qt.openUrlExternally(link)
}
PointingHandLinkHover {}
}
}
}
Flow {
Layout.fillWidth: true
spacing: 5
RippleButtonWithIcon {
materialIcon: "auto_stories"
mainText: Translation.tr("Documentation")
onClicked: {
Qt.openUrlExternally("https://end-4.github.io/dots-hyprland-wiki/en/ii-qs/02usage/")
}
}
RippleButtonWithIcon {
materialIcon: "adjust"
materialIconFill: false
mainText: Translation.tr("Issues")
onClicked: {
Qt.openUrlExternally("https://github.com/end-4/dots-hyprland/issues")
}
}
RippleButtonWithIcon {
materialIcon: "forum"
mainText: Translation.tr("Discussions")
onClicked: {
Qt.openUrlExternally("https://github.com/end-4/dots-hyprland/discussions")
}
}
RippleButtonWithIcon {
materialIcon: "favorite"
mainText: Translation.tr("Donate")
onClicked: {
Qt.openUrlExternally("https://github.com/sponsors/end-4")
}
}
}
}
}
@@ -0,0 +1,45 @@
import QtQuick
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
ContentPage {
forceWidth: true
ContentSection {
title: Translation.tr("Color generation")
ConfigRow {
uniform: true
ConfigSwitch {
text: Translation.tr("Shell & utilities")
checked: Config.options.appearance.wallpaperTheming.enableAppsAndShell
onCheckedChanged: {
Config.options.appearance.wallpaperTheming.enableAppsAndShell = checked;
}
}
ConfigSwitch {
text: Translation.tr("Qt apps")
checked: Config.options.appearance.wallpaperTheming.enableQtApps
onCheckedChanged: {
Config.options.appearance.wallpaperTheming.enableQtApps = checked;
}
StyledToolTip {
content: Translation.tr("Shell & utilities theming must also be enabled")
}
}
ConfigSwitch {
text: Translation.tr("Terminal")
checked: Config.options.appearance.wallpaperTheming.enableTerminal
onCheckedChanged: {
Config.options.appearance.wallpaperTheming.enableTerminal = checked;
}
StyledToolTip {
content: Translation.tr("Shell & utilities theming must also be enabled")
}
}
}
}
}
@@ -0,0 +1,424 @@
import QtQuick
import QtQuick.Layouts
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
ContentPage {
forceWidth: true
ContentSection {
title: Translation.tr("Policies")
ConfigRow {
ColumnLayout {
// Weeb policy
ContentSubsectionLabel {
text: Translation.tr("Weeb")
}
ConfigSelectionArray {
currentValue: Config.options.policies.weeb
configOptionName: "policies.weeb"
onSelected: newValue => {
Config.options.policies.weeb = newValue;
}
options: [
{
displayName: Translation.tr("No"),
value: 0
},
{
displayName: Translation.tr("Yes"),
value: 1
},
{
displayName: Translation.tr("Closet"),
value: 2
}
]
}
}
ColumnLayout {
// AI policy
ContentSubsectionLabel {
text: Translation.tr("AI")
}
ConfigSelectionArray {
currentValue: Config.options.policies.ai
configOptionName: "policies.ai"
onSelected: newValue => {
Config.options.policies.ai = newValue;
}
options: [
{
displayName: Translation.tr("No"),
value: 0
},
{
displayName: Translation.tr("Yes"),
value: 1
},
{
displayName: Translation.tr("Local only"),
value: 2
}
]
}
}
}
}
ContentSection {
title: Translation.tr("Bar")
ConfigSelectionArray {
currentValue: Config.options.bar.cornerStyle
configOptionName: "bar.cornerStyle"
onSelected: newValue => {
Config.options.bar.cornerStyle = newValue;
}
options: [
{
displayName: Translation.tr("Hug"),
value: 0
},
{
displayName: Translation.tr("Float"),
value: 1
},
{
displayName: Translation.tr("Plain rectangle"),
value: 2
}
]
}
ContentSubsection {
title: Translation.tr("Overall appearance")
ConfigRow {
uniform: true
ConfigSwitch {
text: Translation.tr('Borderless')
checked: Config.options.bar.borderless
onCheckedChanged: {
Config.options.bar.borderless = checked;
}
}
ConfigSwitch {
text: Translation.tr('Show background')
checked: Config.options.bar.showBackground
onCheckedChanged: {
Config.options.bar.showBackground = checked;
}
StyledToolTip {
content: Translation.tr("Note: turning off can hurt readability")
}
}
}
}
ContentSubsection {
title: Translation.tr("Buttons")
ConfigRow {
uniform: true
ConfigSwitch {
text: Translation.tr("Screen snip")
checked: Config.options.bar.utilButtons.showScreenSnip
onCheckedChanged: {
Config.options.bar.utilButtons.showScreenSnip = checked;
}
}
ConfigSwitch {
text: Translation.tr("Color picker")
checked: Config.options.bar.utilButtons.showColorPicker
onCheckedChanged: {
Config.options.bar.utilButtons.showColorPicker = checked;
}
}
}
ConfigRow {
uniform: true
ConfigSwitch {
text: Translation.tr("Mic toggle")
checked: Config.options.bar.utilButtons.showMicToggle
onCheckedChanged: {
Config.options.bar.utilButtons.showMicToggle = checked;
}
}
ConfigSwitch {
text: Translation.tr("Keyboard toggle")
checked: Config.options.bar.utilButtons.showKeyboardToggle
onCheckedChanged: {
Config.options.bar.utilButtons.showKeyboardToggle = checked;
}
}
}
ConfigRow {
uniform: true
ConfigSwitch {
text: Translation.tr("Dark/Light toggle")
checked: Config.options.bar.utilButtons.showDarkModeToggle
onCheckedChanged: {
Config.options.bar.utilButtons.showDarkModeToggle = checked;
}
}
ConfigSwitch {
text: Translation.tr("Performance Profile toggle")
checked: Config.options.bar.utilButtons.showPerformanceProfileToggle
onCheckedChanged: {
Config.options.bar.utilButtons.showPerformanceProfileToggle = checked;
}
}
}
}
ContentSubsection {
title: Translation.tr("Workspaces")
tooltip: Translation.tr("Tip: Hide icons and always show numbers for\nthe classic illogical-impulse experience")
ConfigRow {
uniform: true
ConfigSwitch {
text: Translation.tr('Show app icons')
checked: Config.options.bar.workspaces.showAppIcons
onCheckedChanged: {
Config.options.bar.workspaces.showAppIcons = checked;
}
}
ConfigSwitch {
text: Translation.tr('Tint app icons')
checked: Config.options.bar.workspaces.monochromeIcons
onCheckedChanged: {
Config.options.bar.workspaces.monochromeIcons = checked;
}
}
}
ConfigSwitch {
text: Translation.tr('Always show numbers')
checked: Config.options.bar.workspaces.alwaysShowNumbers
onCheckedChanged: {
Config.options.bar.workspaces.alwaysShowNumbers = checked;
}
}
ConfigSpinBox {
text: Translation.tr("Workspaces shown")
value: Config.options.bar.workspaces.shown
from: 1
to: 30
stepSize: 1
onValueChanged: {
Config.options.bar.workspaces.shown = value;
}
}
ConfigSpinBox {
text: Translation.tr("Number show delay when pressing Super (ms)")
value: Config.options.bar.workspaces.showNumberDelay
from: 0
to: 1000
stepSize: 50
onValueChanged: {
Config.options.bar.workspaces.showNumberDelay = value;
}
}
}
ContentSubsection {
title: Translation.tr("Tray")
ConfigSwitch {
text: Translation.tr('Tint icons')
checked: Config.options.bar.tray.monochromeIcons
onCheckedChanged: {
Config.options.bar.tray.monochromeIcons = checked;
}
}
}
ContentSubsection {
title: Translation.tr("Weather")
ConfigSwitch {
text: Translation.tr("Enable")
checked: Config.options.bar.weather.enable
onCheckedChanged: {
Config.options.bar.weather.enable = checked;
}
}
}
}
ContentSection {
title: Translation.tr("Battery")
ConfigRow {
uniform: true
ConfigSpinBox {
text: Translation.tr("Low warning")
value: Config.options.battery.low
from: 0
to: 100
stepSize: 5
onValueChanged: {
Config.options.battery.low = value;
}
}
ConfigSpinBox {
text: Translation.tr("Critical warning")
value: Config.options.battery.critical
from: 0
to: 100
stepSize: 5
onValueChanged: {
Config.options.battery.critical = value;
}
}
}
ConfigRow {
uniform: true
ConfigSwitch {
text: Translation.tr("Automatic suspend")
checked: Config.options.battery.automaticSuspend
onCheckedChanged: {
Config.options.battery.automaticSuspend = checked;
}
StyledToolTip {
content: Translation.tr("Automatically suspends the system when battery is low")
}
}
ConfigSpinBox {
text: Translation.tr("Suspend at")
value: Config.options.battery.suspend
from: 0
to: 100
stepSize: 5
onValueChanged: {
Config.options.battery.suspend = value;
}
}
}
}
ContentSection {
title: Translation.tr("Dock")
ConfigSwitch {
text: Translation.tr("Enable")
checked: Config.options.dock.enable
onCheckedChanged: {
Config.options.dock.enable = checked;
}
}
ConfigRow {
uniform: true
ConfigSwitch {
text: Translation.tr("Hover to reveal")
checked: Config.options.dock.hoverToReveal
onCheckedChanged: {
Config.options.dock.hoverToReveal = checked;
}
}
ConfigSwitch {
text: Translation.tr("Pinned on startup")
checked: Config.options.dock.pinnedOnStartup
onCheckedChanged: {
Config.options.dock.pinnedOnStartup = checked;
}
}
}
ConfigSwitch {
text: Translation.tr("Tint app icons")
checked: Config.options.dock.monochromeIcons
onCheckedChanged: {
Config.options.dock.monochromeIcons = checked;
}
}
}
ContentSection {
title: Translation.tr("Sidebars")
ConfigSwitch {
text: Translation.tr('Keep right sidebar loaded')
checked: Config.options.sidebar.keepRightSidebarLoaded
onCheckedChanged: {
Config.options.sidebar.keepRightSidebarLoaded = checked;
}
StyledToolTip {
content: Translation.tr("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 different kernel might help with this delay")
}
}
}
ContentSection {
title: Translation.tr("On-screen display")
ConfigSpinBox {
text: Translation.tr("Timeout (ms)")
value: Config.options.osd.timeout
from: 100
to: 3000
stepSize: 100
onValueChanged: {
Config.options.osd.timeout = value;
}
}
}
ContentSection {
title: Translation.tr("Overview")
ConfigSwitch {
text: Translation.tr("Enable")
checked: Config.options.overview.enable
onCheckedChanged: {
Config.options.overview.enable = checked;
}
}
ConfigSpinBox {
text: Translation.tr("Scale (%)")
value: Config.options.overview.scale * 100
from: 1
to: 100
stepSize: 1
onValueChanged: {
Config.options.overview.scale = value / 100;
}
}
ConfigRow {
uniform: true
ConfigSpinBox {
text: Translation.tr("Rows")
value: Config.options.overview.rows
from: 1
to: 20
stepSize: 1
onValueChanged: {
Config.options.overview.rows = value;
}
}
ConfigSpinBox {
text: Translation.tr("Columns")
value: Config.options.overview.columns
from: 1
to: 20
stepSize: 1
onValueChanged: {
Config.options.overview.columns = value;
}
}
}
}
ContentSection {
title: Translation.tr("Screenshot tool")
ConfigSwitch {
text: Translation.tr('Show regions of potential interest')
checked: Config.options.screenshotTool.showContentRegions
onCheckedChanged: {
Config.options.screenshotTool.showContentRegions = checked;
}
StyledToolTip {
content: Translation.tr("Such regions 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.")
}
}
}
}
@@ -0,0 +1,233 @@
import QtQuick
import QtQuick.Layouts
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
ContentPage {
forceWidth: true
ContentSection {
title: Translation.tr("Audio")
ConfigSwitch {
text: Translation.tr("Earbang protection")
checked: Config.options.audio.protection.enable
onCheckedChanged: {
Config.options.audio.protection.enable = checked;
}
StyledToolTip {
content: Translation.tr("Prevents abrupt increments and restricts volume limit")
}
}
ConfigRow {
// uniform: true
ConfigSpinBox {
text: Translation.tr("Max allowed increase")
value: Config.options.audio.protection.maxAllowedIncrease
from: 0
to: 100
stepSize: 2
onValueChanged: {
Config.options.audio.protection.maxAllowedIncrease = value;
}
}
ConfigSpinBox {
text: Translation.tr("Volume limit")
value: Config.options.audio.protection.maxAllowed
from: 0
to: 100
stepSize: 2
onValueChanged: {
Config.options.audio.protection.maxAllowed = value;
}
}
}
}
ContentSection {
title: Translation.tr("AI")
MaterialTextField {
Layout.fillWidth: true
placeholderText: Translation.tr("System prompt")
text: Config.options.ai.systemPrompt
wrapMode: TextEdit.Wrap
onTextChanged: {
Qt.callLater(() => {
Config.options.ai.systemPrompt = text;
});
}
}
}
ContentSection {
title: Translation.tr("Battery")
ConfigRow {
uniform: true
ConfigSpinBox {
text: Translation.tr("Low warning")
value: Config.options.battery.low
from: 0
to: 100
stepSize: 5
onValueChanged: {
Config.options.battery.low = value;
}
}
ConfigSpinBox {
text: Translation.tr("Critical warning")
value: Config.options.battery.critical
from: 0
to: 100
stepSize: 5
onValueChanged: {
Config.options.battery.critical = value;
}
}
}
ConfigRow {
uniform: true
ConfigSwitch {
text: Translation.tr("Automatic suspend")
checked: Config.options.battery.automaticSuspend
onCheckedChanged: {
Config.options.battery.automaticSuspend = checked;
}
StyledToolTip {
content: Translation.tr("Automatically suspends the system when battery is low")
}
}
ConfigSpinBox {
text: Translation.tr("Suspend at")
value: Config.options.battery.suspend
from: 0
to: 100
stepSize: 5
onValueChanged: {
Config.options.battery.suspend = value;
}
}
}
}
ContentSection {
title: Translation.tr("Networking")
MaterialTextField {
Layout.fillWidth: true
placeholderText: Translation.tr("User agent (for services that require it)")
text: Config.options.networking.userAgent
wrapMode: TextEdit.Wrap
onTextChanged: {
Config.options.networking.userAgent = text;
}
}
}
ContentSection {
title: Translation.tr("Resources")
ConfigSpinBox {
text: Translation.tr("Polling interval (ms)")
value: Config.options.resources.updateInterval
from: 100
to: 10000
stepSize: 100
onValueChanged: {
Config.options.resources.updateInterval = value;
}
}
}
ContentSection {
title: Translation.tr("Search")
ConfigSwitch {
text: Translation.tr("Use Levenshtein distance-based algorithm instead of fuzzy")
checked: Config.options.search.sloppy
onCheckedChanged: {
Config.options.search.sloppy = checked;
}
StyledToolTip {
content: Translation.tr("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)")
}
}
ContentSubsection {
title: Translation.tr("Prefixes")
ConfigRow {
uniform: true
MaterialTextField {
Layout.fillWidth: true
placeholderText: Translation.tr("Action")
text: Config.options.search.prefix.action
wrapMode: TextEdit.Wrap
onTextChanged: {
Config.options.search.prefix.action = text;
}
}
MaterialTextField {
Layout.fillWidth: true
placeholderText: Translation.tr("Clipboard")
text: Config.options.search.prefix.clipboard
wrapMode: TextEdit.Wrap
onTextChanged: {
Config.options.search.prefix.clipboard = text;
}
}
MaterialTextField {
Layout.fillWidth: true
placeholderText: Translation.tr("Emojis")
text: Config.options.search.prefix.emojis
wrapMode: TextEdit.Wrap
onTextChanged: {
Config.options.search.prefix.emojis = text;
}
}
}
}
ContentSubsection {
title: Translation.tr("Web search")
MaterialTextField {
Layout.fillWidth: true
placeholderText: Translation.tr("Base URL")
text: Config.options.search.engineBaseUrl
wrapMode: TextEdit.Wrap
onTextChanged: {
Config.options.search.engineBaseUrl = text;
}
}
}
}
ContentSection {
title: Translation.tr("Time")
ContentSubsection {
title: Translation.tr("Format")
tooltip: ""
ConfigSelectionArray {
currentValue: Config.options.time.format
configOptionName: "time.format"
onSelected: newValue => {
Config.options.time.format = newValue;
}
options: [
{
displayName: Translation.tr("24h"),
value: "hh:mm"
},
{
displayName: Translation.tr("12h am/pm"),
value: "h:mm ap"
},
{
displayName: Translation.tr("12h AM/PM"),
value: "h:mm AP"
},
]
}
}
}
}
@@ -0,0 +1,215 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
// Main Settings Window
// Integrates transparency settings and other configuration options
ApplicationWindow {
id: settingsWindow
title: "dots-hyprland Settings"
width: 500
height: 700
visible: false
color: "#1e1e2e"
// Make window float and center it
flags: Qt.Window | Qt.WindowStaysOnTopHint
Component.onCompleted: {
// Center the window
x = (Screen.width - width) / 2
y = (Screen.height - height) / 2
}
TabBar {
id: tabBar
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
height: 50
background: Rectangle {
color: "#313244"
}
TabButton {
text: "Effects"
width: implicitWidth
background: Rectangle {
color: parent.checked ? "#45475a" : "transparent"
radius: 4
}
contentItem: Text {
text: parent.text
color: "#cdd6f4"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
TabButton {
text: "Appearance"
width: implicitWidth
background: Rectangle {
color: parent.checked ? "#45475a" : "transparent"
radius: 4
}
contentItem: Text {
text: parent.text
color: "#cdd6f4"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
TabButton {
text: "Keybinds"
width: implicitWidth
background: Rectangle {
color: parent.checked ? "#45475a" : "transparent"
radius: 4
}
contentItem: Text {
text: parent.text
color: "#cdd6f4"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
}
StackLayout {
anchors.top: tabBar.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.margins: 10
currentIndex: tabBar.currentIndex
// Effects Tab (Transparency & Blur)
Item {
TransparencyUI {
anchors.fill: parent
color: "transparent"
border.width: 0
}
}
// Appearance Tab (Future: themes, colors, etc.)
Item {
Rectangle {
anchors.fill: parent
color: "#313244"
radius: 8
Text {
anchors.centerIn: parent
text: "Appearance settings\n(Coming soon)"
color: "#a6adc8"
horizontalAlignment: Text.AlignHCenter
}
}
}
// Keybinds Tab (Future: keybind customization)
Item {
Rectangle {
anchors.fill: parent
color: "#313244"
radius: 8
Text {
anchors.centerIn: parent
text: "Keybind settings\n(Coming soon)"
color: "#a6adc8"
horizontalAlignment: Text.AlignHCenter
}
}
}
}
// Close button
Button {
anchors.top: parent.top
anchors.right: parent.right
anchors.margins: 10
width: 30
height: 30
text: "×"
background: Rectangle {
color: parent.hovered ? "#f38ba8" : "#45475a"
radius: 15
}
contentItem: Text {
text: parent.text
color: "white"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pixelSize: 16
font.bold: true
}
onClicked: settingsWindow.close()
}
// IPC Handler for external control
IpcHandler {
target: "settings"
function show() {
settingsWindow.show()
settingsWindow.raise()
settingsWindow.requestActivate()
}
function hide() {
settingsWindow.hide()
}
function toggle() {
if (settingsWindow.visible) {
settingsWindow.hide()
} else {
settingsWindow.show()
settingsWindow.raise()
settingsWindow.requestActivate()
}
}
function showEffects() {
tabBar.currentIndex = 0
settingsWindow.show()
settingsWindow.raise()
settingsWindow.requestActivate()
}
function showAppearance() {
tabBar.currentIndex = 1
settingsWindow.show()
settingsWindow.raise()
settingsWindow.requestActivate()
}
function showKeybinds() {
tabBar.currentIndex = 2
settingsWindow.show()
settingsWindow.raise()
settingsWindow.requestActivate()
}
}
}
@@ -0,0 +1,245 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Io
import qs
import qs.services
import qs.modules.common
import qs.modules.common.widgets
import qs.modules.common.functions
ContentPage {
baseWidth: lightDarkButtonGroup.implicitWidth
forceWidth: true
Process {
id: konachanWallProc
property string status: ""
command: ["bash", "-c", FileUtils.trimFileProtocol(`${Directories.scriptPath}/colors/random_konachan_wall.sh`)]
stdout: SplitParser {
onRead: data => {
console.log(`Konachan wall proc output: ${data}`);
konachanWallProc.status = data.trim();
}
}
}
ContentSection {
title: Translation.tr("Colors & Wallpaper")
// Light/Dark mode preference
ButtonGroup {
id: lightDarkButtonGroup
Layout.fillWidth: true
LightDarkPreferenceButton {
dark: false
}
LightDarkPreferenceButton {
dark: true
}
}
// Material palette selection
ContentSubsection {
title: Translation.tr("Material palette")
ConfigSelectionArray {
currentValue: Config.options.appearance.palette.type
configOptionName: "appearance.palette.type"
onSelected: (newValue) => {
Config.options.appearance.palette.type = newValue;
Quickshell.execDetached(["bash", "-c", `${Directories.wallpaperSwitchScriptPath} --noswitch`])
}
options: [
{"value": "auto", "displayName": Translation.tr("Auto")},
{"value": "scheme-content", "displayName": Translation.tr("Content")},
{"value": "scheme-expressive", "displayName": Translation.tr("Expressive")},
{"value": "scheme-fidelity", "displayName": Translation.tr("Fidelity")},
{"value": "scheme-fruit-salad", "displayName": Translation.tr("Fruit Salad")},
{"value": "scheme-monochrome", "displayName": Translation.tr("Monochrome")},
{"value": "scheme-neutral", "displayName": Translation.tr("Neutral")},
{"value": "scheme-rainbow", "displayName": Translation.tr("Rainbow")},
{"value": "scheme-tonal-spot", "displayName": Translation.tr("Tonal Spot")}
]
}
}
// Wallpaper selection
ContentSubsection {
title: Translation.tr("Wallpaper")
RowLayout {
Layout.alignment: Qt.AlignHCenter
RippleButtonWithIcon {
id: rndWallBtn
buttonRadius: Appearance.rounding.small
materialIcon: "wallpaper"
mainText: konachanWallProc.running ? Translation.tr("Be patient...") : Translation.tr("Random: Konachan")
onClicked: {
console.log(konachanWallProc.command.join(" "))
konachanWallProc.running = true;
}
StyledToolTip {
content: Translation.tr("Random SFW Anime wallpaper from Konachan\nImage is saved to ~/Pictures/Wallpapers")
}
}
RippleButtonWithIcon {
materialIcon: "wallpaper"
StyledToolTip {
content: Translation.tr("Pick wallpaper image on your system")
}
onClicked: {
Quickshell.execDetached(`${Directories.wallpaperSwitchScriptPath}`)
}
mainContentComponent: Component {
RowLayout {
spacing: 10
StyledText {
font.pixelSize: Appearance.font.pixelSize.small
text: Translation.tr("Choose file")
color: Appearance.colors.colOnSecondaryContainer
}
RowLayout {
spacing: 3
KeyboardKey {
key: "Ctrl"
}
KeyboardKey {
key: "󰖳"
}
StyledText {
Layout.alignment: Qt.AlignVCenter
text: "+"
}
KeyboardKey {
key: "T"
}
}
}
}
}
}
}
StyledText {
Layout.topMargin: 5
Layout.alignment: Qt.AlignHCenter
text: Translation.tr("Alternatively use /dark, /light, /img in the launcher")
font.pixelSize: Appearance.font.pixelSize.smaller
color: Appearance.colors.colSubtext
}
}
ContentSection {
title: Translation.tr("Decorations & Effects")
ContentSubsection {
title: Translation.tr("Transparency")
ConfigRow {
ConfigSwitch {
text: Translation.tr("Enable")
checked: Config.options.appearance.transparency
onCheckedChanged: {
Config.options.appearance.transparency = checked;
}
StyledToolTip {
content: Translation.tr("Might look ass. Unsupported.")
}
}
}
}
ContentSubsection {
title: Translation.tr("Fake screen rounding")
ButtonGroup {
id: fakeScreenRoundingButtonGroup
property int selectedPolicy: Config.options.appearance.fakeScreenRounding
spacing: 2
SelectionGroupButton {
property int value: 0
leftmost: true
buttonText: Translation.tr("No")
toggled: (fakeScreenRoundingButtonGroup.selectedPolicy === value)
onClicked: {
Config.options.appearance.fakeScreenRounding = value;
}
}
SelectionGroupButton {
property int value: 1
buttonText: Translation.tr("Yes")
toggled: (fakeScreenRoundingButtonGroup.selectedPolicy === value)
onClicked: {
Config.options.appearance.fakeScreenRounding = value;
}
}
SelectionGroupButton {
property int value: 2
rightmost: true
buttonText: Translation.tr("When not fullscreen")
toggled: (fakeScreenRoundingButtonGroup.selectedPolicy === value)
onClicked: {
Config.options.appearance.fakeScreenRounding = value;
}
}
}
}
ContentSubsection {
title: Translation.tr("Shell windows")
ConfigRow {
uniform: true
ConfigSwitch {
text: Translation.tr("Title bar")
checked: Config.options.windows.showTitlebar
onCheckedChanged: {
Config.options.windows.showTitlebar = checked;
}
}
ConfigSwitch {
text: Translation.tr("Center title")
checked: Config.options.windows.centerTitle
onCheckedChanged: {
Config.options.windows.centerTitle = checked;
}
}
}
}
ContentSubsection {
title: Translation.tr("Wallpaper parallax")
ConfigRow {
uniform: true
ConfigSwitch {
text: Translation.tr("Depends on workspace")
checked: Config.options.background.parallax.enableWorkspace
onCheckedChanged: {
Config.options.background.parallax.enableWorkspace = checked;
}
}
ConfigSwitch {
text: Translation.tr("Depends on sidebars")
checked: Config.options.background.parallax.enableSidebar
onCheckedChanged: {
Config.options.background.parallax.enableSidebar = checked;
}
}
}
ConfigSpinBox {
text: Translation.tr("Preferred wallpaper zoom (%)")
value: Config.options.background.parallax.workspaceZoom * 100
from: 100
to: 150
stepSize: 1
onValueChanged: {
console.log(value/100)
Config.options.background.parallax.workspaceZoom = value / 100;
}
}
}
}
}
@@ -0,0 +1,209 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import Quickshell.Services.SystemdUser
// Transparency and Blur Settings Module
// Based on AGS configuration from ~/.config/ags/modules/sideright/centermodules/configure.js
Rectangle {
id: transparencySettings
property bool globalTransparency: false
property int terminalOpacity: 100
property bool blurEnabled: false
property bool blurXray: true
property int blurSize: 8
property int blurPasses: 4
// Storage paths (matching AGS structure)
property string colorModeFile: StandardPaths.writableLocation(StandardPaths.CacheLocation) + "/ags/user/colormode.txt"
property string terminalTransparencyFile: StandardPaths.writableLocation(StandardPaths.CacheLocation) + "/ags/user/generated/terminal/transparency"
color: "transparent"
Component.onCompleted: {
loadSettings()
}
// Load settings from files (AGS compatibility)
function loadSettings() {
// Load global transparency mode
Process.exec("bash", ["-c", `mkdir -p $(dirname "${colorModeFile}")`])
let colorModeResult = Process.exec("bash", ["-c", `sed -n '2p' "${colorModeFile}" 2>/dev/null || echo "opaque"`])
globalTransparency = (colorModeResult.stdout.trim() === "transparent")
// Load terminal opacity
Process.exec("bash", ["-c", `mkdir -p $(dirname "${terminalTransparencyFile}")`])
let termOpacityResult = Process.exec("bash", ["-c", `cat "${terminalTransparencyFile}" 2>/dev/null || echo "100"`])
terminalOpacity = parseInt(termOpacityResult.stdout.trim()) || 100
// Load Hyprland blur settings
loadHyprlandSettings()
}
function loadHyprlandSettings() {
// Load blur enabled
let blurResult = Process.exec("hyprctl", ["getoption", "-j", "decoration:blur:enabled"])
try {
let blurData = JSON.parse(blurResult.stdout)
blurEnabled = blurData.int !== 0
} catch (e) {
console.log("Failed to load blur enabled setting:", e)
}
// Load blur xray
let xrayResult = Process.exec("hyprctl", ["getoption", "-j", "decoration:blur:xray"])
try {
let xrayData = JSON.parse(xrayResult.stdout)
blurXray = xrayData.int !== 0
} catch (e) {
console.log("Failed to load blur xray setting:", e)
}
// Load blur size
let sizeResult = Process.exec("hyprctl", ["getoption", "-j", "decoration:blur:size"])
try {
let sizeData = JSON.parse(sizeResult.stdout)
blurSize = sizeData.int
} catch (e) {
console.log("Failed to load blur size setting:", e)
}
// Load blur passes
let passesResult = Process.exec("hyprctl", ["getoption", "-j", "decoration:blur:passes"])
try {
let passesData = JSON.parse(passesResult.stdout)
blurPasses = passesData.int
} catch (e) {
console.log("Failed to load blur passes setting:", e)
}
}
// Save and apply global transparency
function setGlobalTransparency(enabled) {
globalTransparency = enabled
let mode = enabled ? "transparent" : "opaque"
// Save to colormode.txt (line 2)
Process.exec("bash", ["-c", `mkdir -p $(dirname "${colorModeFile}")
if [ ! -f "${colorModeFile}" ]; then
echo "dark" > "${colorModeFile}"
echo "${mode}" >> "${colorModeFile}"
else
sed -i "2s/.*/${mode}/" "${colorModeFile}"
fi`])
// Apply color changes (equivalent to AGS switchcolor.sh)
applyColorChanges()
}
// Save and apply terminal opacity
function setTerminalOpacity(opacity) {
terminalOpacity = opacity
// Save to terminal transparency file
Process.exec("bash", ["-c", `mkdir -p $(dirname "${terminalTransparencyFile}")
echo "${opacity}" > "${terminalTransparencyFile}"`])
// Apply terminal colors (equivalent to AGS applycolor.sh term)
applyTerminalColors()
}
// Apply Hyprland blur settings
function setBlurEnabled(enabled) {
blurEnabled = enabled
Process.exec("hyprctl", ["keyword", "decoration:blur:enabled", enabled ? "1" : "0"])
}
function setBlurXray(enabled) {
blurXray = enabled
Process.exec("hyprctl", ["keyword", "decoration:blur:xray", enabled ? "1" : "0"])
}
function setBlurSize(size) {
blurSize = size
Process.exec("hyprctl", ["keyword", "decoration:blur:size", size.toString()])
}
function setBlurPasses(passes) {
blurPasses = passes
Process.exec("hyprctl", ["keyword", "decoration:blur:passes", passes.toString()])
}
// Apply color changes (equivalent to AGS color generation)
function applyColorChanges() {
// This would call the equivalent of AGS color generation scripts
Process.exec("bash", ["-c", `
# Apply transparency mode to all shell elements
# This is where we'd integrate with the quickshell theming system
echo "Applying transparency mode: ${globalTransparency ? 'transparent' : 'opaque'}"
# Reload quickshell to apply changes
quickshell ipc call settings reload || true
`])
}
// Apply terminal colors (equivalent to AGS applycolor.sh term)
function applyTerminalColors() {
let alpha = terminalOpacity / 100.0
Process.exec("bash", ["-c", `
# Update foot terminal configuration with new opacity
FOOT_CONFIG="$HOME/.config/foot/foot.ini"
if [ -f "$FOOT_CONFIG" ]; then
# Update alpha value in foot.ini
sed -i "s/^alpha=.*/alpha=${alpha}/" "$FOOT_CONFIG" || echo "alpha=${alpha}" >> "$FOOT_CONFIG"
fi
# Send terminal escape sequence to update running terminals
# This matches the AGS terminal sequences functionality
echo "Applied terminal opacity: ${terminalOpacity}%"
`])
}
// IPC Handler for external control
IpcHandler {
target: "transparencySettings"
function setTransparency(enabled) {
transparencySettings.setGlobalTransparency(enabled)
}
function setTerminalOpacity(opacity) {
transparencySettings.setTerminalOpacity(opacity)
}
function setBlur(enabled) {
transparencySettings.setBlurEnabled(enabled)
}
function setBlurXray(enabled) {
transparencySettings.setBlurXray(enabled)
}
function setBlurSize(size) {
transparencySettings.setBlurSize(size)
}
function setBlurPasses(passes) {
transparencySettings.setBlurPasses(passes)
}
function getSettings() {
return {
globalTransparency: transparencySettings.globalTransparency,
terminalOpacity: transparencySettings.terminalOpacity,
blurEnabled: transparencySettings.blurEnabled,
blurXray: transparencySettings.blurXray,
blurSize: transparencySettings.blurSize,
blurPasses: transparencySettings.blurPasses
}
}
function reload() {
transparencySettings.loadSettings()
}
}
}
@@ -0,0 +1,469 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
// Transparency and Blur UI Controls
// Replicates the AGS configuration UI from configure.js
Rectangle {
id: transparencyUI
property alias transparencySettings: settingsLoader.item
width: 400
height: 600
color: "#1e1e2e"
radius: 12
border.color: "#45475a"
border.width: 1
// Load the settings module
Loader {
id: settingsLoader
source: "TransparencySettings.qml"
}
ScrollView {
anchors.fill: parent
anchors.margins: 20
ColumnLayout {
width: parent.width
spacing: 20
// Header
Text {
text: "Effects Configuration"
color: "#cdd6f4"
font.pixelSize: 18
font.bold: true
Layout.fillWidth: true
}
// Global Transparency Section
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: transparencySection.height + 20
color: "#313244"
radius: 8
ColumnLayout {
id: transparencySection
anchors.fill: parent
anchors.margins: 15
spacing: 15
// Transparency Toggle
RowLayout {
Layout.fillWidth: true
Rectangle {
width: 24
height: 24
color: "#89b4fa"
radius: 4
Text {
anchors.centerIn: parent
text: "◫"
color: "white"
font.pixelSize: 14
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: 2
Text {
text: "Transparency"
color: "#cdd6f4"
font.pixelSize: 14
font.bold: true
}
Text {
text: "Make shell elements transparent\nBlur is also recommended if you enable this"
color: "#a6adc8"
font.pixelSize: 11
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
}
Switch {
id: transparencySwitch
checked: transparencySettings ? transparencySettings.globalTransparency : false
onToggled: {
if (transparencySettings) {
transparencySettings.setGlobalTransparency(checked)
}
}
}
}
// Terminal Opacity Slider (subcategory)
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: terminalOpacitySection.height + 10
color: "#45475a"
radius: 6
Layout.leftMargin: 20
ColumnLayout {
id: terminalOpacitySection
anchors.fill: parent
anchors.margins: 10
spacing: 10
RowLayout {
Layout.fillWidth: true
Rectangle {
width: 20
height: 20
color: "#f9e2af"
radius: 3
Text {
anchors.centerIn: parent
text: "○"
color: "black"
font.pixelSize: 12
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: 2
Text {
text: "Terminal Opacity"
color: "#cdd6f4"
font.pixelSize: 13
font.bold: true
}
Text {
text: "Changes the opacity of the foot terminal"
color: "#a6adc8"
font.pixelSize: 10
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
}
Text {
text: (transparencySettings ? transparencySettings.terminalOpacity : 100) + "%"
color: "#cdd6f4"
font.pixelSize: 12
Layout.preferredWidth: 40
}
}
Slider {
id: terminalOpacitySlider
Layout.fillWidth: true
from: 0
to: 100
stepSize: 1
value: transparencySettings ? transparencySettings.terminalOpacity : 100
onValueChanged: {
if (transparencySettings && Math.abs(value - transparencySettings.terminalOpacity) > 0.5) {
transparencySettings.setTerminalOpacity(Math.round(value))
}
}
}
}
}
}
}
// Blur Section
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: blurSection.height + 20
color: "#313244"
radius: 8
ColumnLayout {
id: blurSection
anchors.fill: parent
anchors.margins: 15
spacing: 15
// Blur Toggle
RowLayout {
Layout.fillWidth: true
Rectangle {
width: 24
height: 24
color: "#94e2d5"
radius: 4
Text {
anchors.centerIn: parent
text: "◐"
color: "black"
font.pixelSize: 14
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: 2
Text {
text: "Blur"
color: "#cdd6f4"
font.pixelSize: 14
font.bold: true
}
Text {
text: "Enable blur on transparent elements\nDoesn't affect performance/power consumption unless you have transparent windows."
color: "#a6adc8"
font.pixelSize: 11
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
}
Switch {
id: blurSwitch
checked: transparencySettings ? transparencySettings.blurEnabled : false
onToggled: {
if (transparencySettings) {
transparencySettings.setBlurEnabled(checked)
}
}
}
}
// Blur Subcategory
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: blurSubcategory.height + 10
color: "#45475a"
radius: 6
Layout.leftMargin: 20
visible: transparencySettings ? transparencySettings.blurEnabled : false
ColumnLayout {
id: blurSubcategory
anchors.fill: parent
anchors.margins: 10
spacing: 15
// X-ray Toggle
RowLayout {
Layout.fillWidth: true
Rectangle {
width: 20
height: 20
color: "#f38ba8"
radius: 3
Text {
anchors.centerIn: parent
text: "⚡"
color: "white"
font.pixelSize: 10
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: 2
Text {
text: "X-ray"
color: "#cdd6f4"
font.pixelSize: 13
font.bold: true
}
Text {
text: "Make everything behind a window/layer except the wallpaper not rendered on its blurred surface\nRecommended to improve performance (if you don't abuse transparency/blur)"
color: "#a6adc8"
font.pixelSize: 10
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
}
Switch {
checked: transparencySettings ? transparencySettings.blurXray : true
onToggled: {
if (transparencySettings) {
transparencySettings.setBlurXray(checked)
}
}
}
}
// Blur Size
RowLayout {
Layout.fillWidth: true
Rectangle {
width: 20
height: 20
color: "#a6e3a1"
radius: 3
Text {
anchors.centerIn: parent
text: "◎"
color: "black"
font.pixelSize: 10
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: 2
Text {
text: "Size"
color: "#cdd6f4"
font.pixelSize: 13
font.bold: true
}
Text {
text: "Adjust the blur radius. Generally doesn't affect performance\nHigher = more color spread"
color: "#a6adc8"
font.pixelSize: 10
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
}
SpinBox {
from: 1
to: 1000
value: transparencySettings ? transparencySettings.blurSize : 8
onValueChanged: {
if (transparencySettings && value !== transparencySettings.blurSize) {
transparencySettings.setBlurSize(value)
}
}
}
}
// Blur Passes
RowLayout {
Layout.fillWidth: true
Rectangle {
width: 20
height: 20
color: "#cba6f7"
radius: 3
Text {
anchors.centerIn: parent
text: "↻"
color: "white"
font.pixelSize: 10
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: 2
Text {
text: "Passes"
color: "#cdd6f4"
font.pixelSize: 13
font.bold: true
}
Text {
text: "Adjust the number of runs of the blur algorithm\nMore passes = more spread and power consumption\n4 is recommended\n2- would look weird and 6+ would look lame."
color: "#a6adc8"
font.pixelSize: 10
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
}
SpinBox {
from: 1
to: 10
value: transparencySettings ? transparencySettings.blurPasses : 4
onValueChanged: {
if (transparencySettings && value !== transparencySettings.blurPasses) {
transparencySettings.setBlurPasses(value)
}
}
}
}
}
}
}
}
// Apply/Reset buttons
RowLayout {
Layout.fillWidth: true
Layout.topMargin: 20
Button {
text: "Reset to Defaults"
Layout.fillWidth: true
onClicked: {
if (transparencySettings) {
transparencySettings.setGlobalTransparency(false)
transparencySettings.setTerminalOpacity(100)
transparencySettings.setBlurEnabled(false)
transparencySettings.setBlurXray(true)
transparencySettings.setBlurSize(8)
transparencySettings.setBlurPasses(4)
}
}
}
Button {
text: "Reload Settings"
Layout.fillWidth: true
onClicked: {
if (transparencySettings) {
transparencySettings.loadSettings()
}
}
}
}
}
}
// IPC Handler for external control
IpcHandler {
target: "transparencyUI"
function show() {
transparencyUI.visible = true
}
function hide() {
transparencyUI.visible = false
}
function toggle() {
transparencyUI.visible = !transparencyUI.visible
}
}
}