Renamed all services to xxxService. Moved a couple things in Commons

This commit is contained in:
quadbyte 2025-08-15 21:45:58 -04:00
parent 7e334ae768
commit 83ff5f5589
86 changed files with 275 additions and 211 deletions

133
Commons/Colors.qml Normal file
View file

@ -0,0 +1,133 @@
pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Io
import qs.Commons
import qs.Services
// --------------------------------
// Noctalia Colors - Material Design 3
// We only use a very small subset of all available m3 colors to avoid complexity
// All color names start with a 'm' to avoid QML assuming some of them are signals (ex: onPrimary)
Singleton {
id: root
// --- Key Colors: These are the main accent colors that define your app's style
property color mPrimary: customColors.mPrimary
property color mOnPrimary: customColors.mOnPrimary
property color mSecondary: customColors.mSecondary
property color mOnSecondary: customColors.mOnSecondary
property color mTertiary: customColors.mTertiary
property color mOnTertiary: customColors.mOnTertiary
// --- Utility Colors: These colors serve specific, universal purposes like indicating errors
property color mError: customColors.mError
property color mOnError: customColors.mOnError
// --- Surface and Variant Colors: These provide additional options for surfaces and their contents, creating visual hierarchy
property color mSurface: customColors.mSurface
property color mOnSurface: customColors.mOnSurface
property color mSurfaceVariant: customColors.mSurfaceVariant
property color mOnSurfaceVariant: customColors.mOnSurfaceVariant
property color mOutline: customColors.mOutline
property color mOutlineVariant: customColors.mOutlineVariant
property color mShadow: customColors.mShadow
// -----------
function applyOpacity(color, opacity) {
// Convert color to string and apply opacity
return color.toString().replace("#", "#" + opacity)
}
// --------------------------------
// Default colors: RosePine
QtObject {
id: defaultColors
property color mPrimary: "#ebbcba"
property color mOnPrimary: "#1f1d2e"
property color mSecondary: "#31748f"
property color mOnSecondary: "#e0def4"
property color mTertiary: "#9ccfd8"
property color mOnTertiary: "#191724"
property color mError: "#eb6f92"
property color mOnError: "#1f1d2e"
property color mSurface: "#1f1d2e"
property color mOnSurface: "#e0def4"
property color mSurfaceVariant: "#26233a"
property color mOnSurfaceVariant: "#908caa"
property color mOutline: "#44415a"
property color mOutlineVariant: "#514e6c"
property color mShadow: "#191724"
}
// ----------------------------------------------------------------
// Custom colors loaded from colors.json
// These can be generated by matugen or simply come from a well know color scheme (Dracula, Gruvbox, Nord, ...)
QtObject {
id: customColors
property color mPrimary: customColorsData.mPrimary
property color mOnPrimary: customColorsData.mOnPrimary
property color mSecondary: customColorsData.mSecondary
property color mOnSecondary: customColorsData.mOnSecondary
property color mTertiary: customColorsData.mTertiary
property color mOnTertiary: customColorsData.mOnTertiary
property color mError: customColorsData.mError
property color mOnError: customColorsData.mOnError
property color mSurface: customColorsData.mSurface
property color mOnSurface: customColorsData.mOnSurface
property color mSurfaceVariant: customColorsData.mSurfaceVariant
property color mOnSurfaceVariant: customColorsData.mOnSurfaceVariant
property color mOutline: customColorsData.mOutline
property color mOutlineVariant: customColorsData.mOutlineVariant
property color mShadow: customColorsData.mShadow
}
// FileView to load custom colors data from colors.json
FileView {
id: customColorsFile
path: Settings.configDir + "colors.json"
watchChanges: true
onFileChanged: {
console.log("[Colors] Reloading colors from disk")
reload()
}
onAdapterUpdated: {
console.log("[Colors] Writing colors to disk")
writeAdapter()
}
onLoadFailed: function (error) {
if (error.toString().includes("No such file") || error === 2) {
// File doesn't exist, create it with default values
writeAdapter()
}
}
JsonAdapter {
id: customColorsData
property color mPrimary: defaultColors.mPrimary
property color mOnPrimary: defaultColors.mOnPrimary
property color mSecondary: defaultColors.mSecondary
property color mOnSecondary: defaultColors.mOnSecondary
property color mTertiary: defaultColors.mTertiary
property color mOnTertiary: defaultColors.mOnTertiary
property color mError: defaultColors.mError
property color mOnError: defaultColors.mOnError
property color mSurface: defaultColors.mSurface
property color mOnSurface: defaultColors.mOnSurface
property color mSurfaceVariant: defaultColors.mSurfaceVariant
property color mOnSurfaceVariant: defaultColors.mOnSurfaceVariant
property color mOutline: defaultColors.mOutline
property color mOutlineVariant: defaultColors.mOutlineVariant
property color mShadow: defaultColors.mShadow
}
}
}

60
Commons/IPCManager.qml Normal file
View file

@ -0,0 +1,60 @@
import QtQuick
import Quickshell.Io
Item {
id: root
IpcHandler {
target: "settings"
function toggle() {
settingsPanel.isLoaded = !settingsPanel.isLoaded
}
}
IpcHandler {
target: "notifications"
function toggleHistory() {
notificationHistoryPanel.isLoaded = !notificationHistoryPanel.isLoaded
}
function toggleDoNotDisturb() {// TODO
}
}
IpcHandler {
target: "idleInhibitor"
function toggle() {// TODO
}
}
IpcHandler {
target: "appLauncher"
function toggle() {
appLauncherPanel.isLoaded = !appLauncherPanel.isLoaded
}
}
IpcHandler {
target: "lockScreen"
function toggle() {
lockScreen.locked = !lockScreen.locked
}
}
IpcHandler {
target: "brightness"
function increase() {
BrightnessService.increaseBrightness()
}
function decrease() {
BrightnessService.decreaseBrightness()
}
}
}

202
Commons/Settings.qml Normal file
View file

@ -0,0 +1,202 @@
import QtQuick
import Quickshell
import Quickshell.Io
import qs.Commons
import qs.Services
pragma Singleton
Singleton {
id: root
// Define our app directories
// Default config directory: ~/.config/noctalia
// Default cache directory: ~/.cache/noctalia
property string shellName: "noctalia"
property string configDir: Quickshell.env("NOCTALIA_CONFIG_DIR") || (Quickshell.env("XDG_CONFIG_HOME")
|| Quickshell.env(
"HOME") + "/.config") + "/" + shellName + "/"
property string cacheDir: Quickshell.env("NOCTALIA_CACHE_DIR") || (Quickshell.env("XDG_CACHE_HOME") || Quickshell.env(
"HOME") + "/.cache") + "/" + shellName + "/"
property string settingsFile: Quickshell.env("NOCTALIA_SETTINGS_FILE") || (configDir + "settings.json")
property string defaultWallpaper: Qt.resolvedUrl("../Assets/Tests/wallpaper.png")
property string defaultAvatar: Quickshell.env("HOME") + "/.face"
// Used to access via Settings.data.xxx.yyy
property var data: adapter
// Flag to prevent unnecessary wallpaper calls during reloads
property bool isInitialLoad: true
// Needed to only have one NPanel loaded at a time. <--- VERY BROKEN
//property var openPanel: null
Item {
Component.onCompleted: {
// ensure settings dir exists
Quickshell.execDetached(["mkdir", "-p", configDir])
Quickshell.execDetached(["mkdir", "-p", cacheDir])
}
}
FileView {
path: settingsFile
watchChanges: true
onFileChanged: reload()
onAdapterUpdated: writeAdapter()
Component.onCompleted: function () {
reload()
}
onLoaded: function () {
console.log("[Settings] Loaded")
Qt.callLater(function () {
// Only set wallpaper on initial load, not on reloads
if (isInitialLoad && adapter.wallpaper.current !== "") {
console.log("[Settings] Set current wallpaper", adapter.wallpaper.current)
WallpapersService.setCurrentWallpaper(adapter.wallpaper.current, true)
}
isInitialLoad = false
})
}
onLoadFailed: function (error) {
if (error.toString().includes("No such file") || error === 2)
// File doesn't exist, create it with default values
writeAdapter()
}
JsonAdapter {
id: adapter
// bar
property JsonObject bar
bar: JsonObject {
property bool showActiveWindow: true
property bool showSystemInfo: false
property bool showMedia: false
property bool showTaskbar: false
property list<string> monitors: []
}
// general
property JsonObject general
general: JsonObject {
property string avatarImage: defaultAvatar
property bool dimDesktop: true
property bool showScreenCorners: false
}
// location
property JsonObject location
location: JsonObject {
property string name: "Tokyo"
property bool useFahrenheit: false
property bool reverseDayMonth: false
property bool use12HourClock: false
}
// screen recorder
property JsonObject screenRecorder
screenRecorder: JsonObject {
property string directory: "~/Videos"
property int frameRate: 60
property string audioCodec: "opus"
property string videoCodec: "h264"
property string quality: "very_high"
property string colorRange: "limited"
property bool showCursor: true
property string audioSource: "default_output"
}
// wallpaper
property JsonObject wallpaper
wallpaper: JsonObject {
property string directory: "/usr/share/wallpapers"
property string current: ""
property bool isRandom: false
property int randomInterval: 300
property JsonObject swww
onDirectoryChanged: WallpapersService.loadWallpapers()
onIsRandomChanged: WallpapersService.toggleRandomWallpaper()
onRandomIntervalChanged: WallpapersService.restartRandomWallpaperTimer()
swww: JsonObject {
property bool enabled: false
property string resizeMethod: "crop"
property int transitionFps: 60
property string transitionType: "random"
property real transitionDuration: 1.1
}
}
// applauncher
property JsonObject appLauncher
appLauncher: JsonObject {
property list<string> pinnedExecs: []
}
// dock
property JsonObject dock
dock: JsonObject {
property bool autoHide: false
property bool exclusive: false
property list<string> monitors: []
}
// network
property JsonObject network
network: JsonObject {
property bool wifiEnabled: true
property bool bluetoothEnabled: true
}
// notifications
property JsonObject notifications
notifications: JsonObject {
property list<string> monitors: []
}
// audio
property JsonObject audio
audio: JsonObject {
property string visualizerType: "linear"
}
// ui
property JsonObject ui
ui: JsonObject {
property string fontFamily: "Roboto" // Family for all text
property list<string> monitorsScale: []
}
// brightness
property JsonObject brightness
brightness: JsonObject {
property real lastBrightness: 50.0
property string lastMethod: "internal"
property list<var> monitorBrightness: []
property int brightnessStep: 5
}
property JsonObject colorSchemes
colorSchemes: JsonObject {
property bool useWallpaperColors: false
property string predefinedScheme: ""
}
}
}
}

71
Commons/Style.qml Normal file
View file

@ -0,0 +1,71 @@
pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Io
Singleton {
id: root
/*
Preset sizes for font, radii, ?
*/
// Font size
property real fontSizeTiny: 7
property real fontSizeSmall: 9
property real fontSizeMedium: 11
property real fontSizeInter: 12
property real fontSizeLarge: 13
property real fontSizeLarger: 16
property real fontSizeXL: 18
property real fontSizeXXL: 24
// Font weight / Unsure if we keep em?
property int fontWeightRegular: 400
property int fontWeightMedium: 500
property int fontWeightBold: 700
// Radii
property int radiusTiny: 8
property int radiusSmall: 12
property int radiusMedium: 16
property int radiusLarge: 20
// Border
property int borderThin: 1
property int borderMedium: 2
property int borderThick: 3
// Animation duration (ms)
property int animationFast: 150
property int animationNormal: 300
property int animationSlow: 500
// Dimensions
property int barHeight: 36
property int baseWidgetSize: 32
property int sliderWidth: 200
// Delays
property int tooltipDelay: 300
property int tooltipDelayLong: 1200
property int pillDelay: 500
// Margins (for margins and spacing)
property int marginTiniest: 2
property int marginTiny: 4
property int marginSmall: 8
property int marginMedium: 12
property int marginLarge: 16
property int marginXL: 24
// Opacity
property real opacityNone: 0.0
property real opacityLight: 0.25
property real opacityMedium: 0.5
property real opacityHeavy: 0.75
property real opacityAlmost: 0.95
property real opacityFull: 1.0
}

94
Commons/Time.qml Normal file
View file

@ -0,0 +1,94 @@
pragma Singleton
import Quickshell
import QtQuick
import qs.Commons
import qs.Services
Singleton {
id: root
property var date: new Date()
property string time: Settings.data.location.use12HourClock ? Qt.formatDateTime(date, "h:mm AP") : Qt.formatDateTime(
date, "HH:mm")
readonly property string dateString: {
let now = date
let dayName = now.toLocaleDateString(Qt.locale(), "ddd")
dayName = dayName.charAt(0).toUpperCase() + dayName.slice(1)
let day = now.getDate()
let suffix
if (day > 3 && day < 21)
suffix = 'th'
else
switch (day % 10) {
case 1:
suffix = "st"
break
case 2:
suffix = "nd"
break
case 3:
suffix = "rd"
break
default:
suffix = "th"
}
let month = now.toLocaleDateString(Qt.locale(), "MMMM")
let year = now.toLocaleDateString(Qt.locale(), "yyyy")
return `${dayName}, `
+ (Settings.data.location.reverseDayMonth ? `${month} ${day}${suffix} ${year}` : `${day}${suffix} ${month} ${year}`)
}
// Returns a Unix Timestamp (in seconds)
readonly property int timestamp: {
return Math.floor(date / 1000)
}
/**
* Formats a Date object into a YYYYMMDD-HHMMSS string.
* @param {Date} [date=new Date()] - The date to format. Defaults to the current date and time.
* @returns {string} The formatted date string.
*/
function getFormattedTimestamp(date = new Date()) {
const year = date.getFullYear()
// getMonth() is zero-based, so we add 1
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
const hours = String(date.getHours()).padStart(2, '0')
const minutes = String(date.getMinutes()).padStart(2, '0')
const seconds = String(date.getSeconds()).padStart(2, '0')
return `${year}${month}${day}-${hours}${minutes}${seconds}`
}
// Format an easy to read approximate duration ex: 4h32m
// Used to display the time remaining on the Battery widget
function formatVagueHumanReadableDuration(totalSeconds) {
const hours = Math.floor(totalSeconds / 3600)
const minutes = Math.floor((totalSeconds - (hours * 3600)) / 60)
const seconds = totalSeconds - (hours * 3600) - (minutes * 60)
var str = ""
if (hours) {
str += hours.toString() + "h"
}
if (minutes) {
str += minutes.toString() + "m"
}
if (!hours && !minutes) {
str += seconds.toString() + "s"
}
return str
}
Timer {
interval: 1000
repeat: true
running: true
onTriggered: root.date = new Date()
}
}