diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 094beb6..703a0c1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -27,30 +27,19 @@ jobs: mv *.tar.gz ${{ github.workspace }}/ - name: Generate release notes - id: release_notes run: | - PREV_TAG=$(git describe --tags --abbrev=0 @^ 2>/dev/null || echo "") - RANGE="${PREV_TAG}..HEAD" - - PR_NOTES="" - COMMIT_NOTES="" - - git log $RANGE --pretty=format:"%H|%s|%an" | while IFS='|' read -r SHA MSG AUTHOR; do - SHORT_MSG=$(echo "$MSG" | cut -c1-80) - if [[ "$MSG" =~ Merge\ pull\ request\ \#([0-9]+) ]]; then - PR_NUM="${BASH_REMATCH[1]}" - PR_TITLE=$(echo "$SHORT_MSG" | sed -E "s/Merge pull request #$PR_NUM //") - PR_NOTES+="- [PR #$PR_NUM](https://github.com/${GITHUB_REPOSITORY}/pull/$PR_NUM): $PR_TITLE by $AUTHOR\n" - else - COMMIT_NOTES+="- [$SHA](https://github.com/${GITHUB_REPOSITORY}/commit/$SHA): $SHORT_MSG by $AUTHOR\n" - fi - done - - NOTES="### Merged PRs\n$PR_NOTES\n### Direct commits\n$COMMIT_NOTES" - - echo "RELEASE_NOTES<> $GITHUB_ENV - echo -e "$NOTES" >> $GITHUB_ENV - echo "EOF" >> $GITHUB_ENV + PREV_TAG=$(git describe --tags --abbrev=0 ${{ github.ref }}^ 2>/dev/null || echo "") + if [ -z "$PREV_TAG" ]; then + RANGE=$(git rev-list --max-parents=0 HEAD)..HEAD + else + RANGE=$PREV_TAG..HEAD + fi + echo "# Release ${{ github.ref_name }}" > release_notes.md + echo "" >> release_notes.md + echo "## Changes since $PREV_TAG" >> release_notes.md + echo "" >> release_notes.md + git log $RANGE --pretty=format:"- %s ([%h](https://github.com/${{ github.repository }}/commit/%H)) by %an" >> release_notes.md + echo "" >> release_notes.md - name: Create GitHub Release uses: softprops/action-gh-release@v1 @@ -58,6 +47,6 @@ jobs: files: | noctalia-${{ github.ref_name }}.tar.gz noctalia-latest.tar.gz - body: ${{ env.RELEASE_NOTES }} + body_path: release_notes.md env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/Helpers/MathHelper.js b/Helpers/MathHelper.js deleted file mode 100644 index cc86775..0000000 --- a/Helpers/MathHelper.js +++ /dev/null @@ -1,120 +0,0 @@ -// Math helper functions for calculator functionality -var MathHelper = { - // Basic arithmetic operations - add: (a, b) => a + b, - subtract: (a, b) => a - b, - multiply: (a, b) => a * b, - divide: (a, b) => b !== 0 ? a / b : NaN, - - // Power and roots - pow: (base, exponent) => Math.pow(base, exponent), - sqrt: (x) => x >= 0 ? Math.sqrt(x) : NaN, - cbrt: (x) => Math.cbrt(x), - - // Trigonometric functions (in radians) - sin: (x) => Math.sin(x), - cos: (x) => Math.cos(x), - tan: (x) => Math.tan(x), - asin: (x) => Math.asin(x), - acos: (x) => Math.acos(x), - atan: (x) => Math.atan(x), - - // Logarithmic functions - log: (x) => x > 0 ? Math.log(x) : NaN, - log10: (x) => x > 0 ? Math.log10(x) : NaN, - log2: (x) => x > 0 ? Math.log2(x) : NaN, - - // Other mathematical functions - abs: (x) => Math.abs(x), - floor: (x) => Math.floor(x), - ceil: (x) => Math.ceil(x), - round: (x) => Math.round(x), - min: (...args) => Math.min(...args), - max: (...args) => Math.max(...args), - - // Constants - PI: Math.PI, - E: Math.E, - - // Factorial - factorial: (n) => { - if (n < 0 || n !== Math.floor(n)) return NaN; - if (n === 0 || n === 1) return 1; - let result = 1; - for (let i = 2; i <= n; i++) { - result *= i; - } - return result; - }, - - // Percentage - percent: (value, total) => (value / total) * 100, - - // Degrees to radians and vice versa - toRadians: (degrees) => degrees * (Math.PI / 180), - toDegrees: (radians) => radians * (180 / Math.PI), - - // Safe evaluation with math functions - evaluate: (expression) => { - try { - // Replace common math functions with MathHelper equivalents - let processedExpr = expression - .replace(/\bpi\b/gi, 'MathHelper.PI') - .replace(/\be\b/gi, 'MathHelper.E') - .replace(/\bsin\b/gi, 'MathHelper.sin') - .replace(/\bcos\b/gi, 'MathHelper.cos') - .replace(/\btan\b/gi, 'MathHelper.tan') - .replace(/\basin\b/gi, 'MathHelper.asin') - .replace(/\bacos\b/gi, 'MathHelper.acos') - .replace(/\batan\b/gi, 'MathHelper.atan') - .replace(/\blog\b/gi, 'MathHelper.log') - .replace(/\blog10\b/gi, 'MathHelper.log10') - .replace(/\blog2\b/gi, 'MathHelper.log2') - .replace(/\bsqrt\b/gi, 'MathHelper.sqrt') - .replace(/\bcbrt\b/gi, 'MathHelper.cbrt') - .replace(/\bpow\b/gi, 'MathHelper.pow') - .replace(/\babs\b/gi, 'MathHelper.abs') - .replace(/\bfloor\b/gi, 'MathHelper.floor') - .replace(/\bceil\b/gi, 'MathHelper.ceil') - .replace(/\bround\b/gi, 'MathHelper.round') - .replace(/\bmin\b/gi, 'MathHelper.min') - .replace(/\bmax\b/gi, 'MathHelper.max') - .replace(/\bfactorial\b/gi, 'MathHelper.factorial') - .replace(/\bpercent\b/gi, 'MathHelper.percent') - .replace(/\btoRadians\b/gi, 'MathHelper.toRadians') - .replace(/\btoDegrees\b/gi, 'MathHelper.toDegrees'); - - // Evaluate the expression - const result = Function('MathHelper', 'return ' + processedExpr)(MathHelper); - - // Check if result is valid - if (isNaN(result) || !isFinite(result)) { - return null; - } - - return result; - } catch (error) { - return null; - } - }, - - // Format result for display - formatResult: (result) => { - if (result === null || isNaN(result) || !isFinite(result)) { - return "Error"; - } - - // For very large or small numbers, use scientific notation - if (Math.abs(result) >= 1e10 || (Math.abs(result) < 1e-10 && result !== 0)) { - return result.toExponential(6); - } - - // For integers, don't show decimal places - if (Number.isInteger(result)) { - return result.toString(); - } - - // For decimals, limit to 8 significant digits - return parseFloat(result.toPrecision(8)).toString(); - } -}; \ No newline at end of file diff --git a/Modules/AppLauncher/AppLauncher.qml b/Modules/AppLauncher/AppLauncher.qml index d296f62..885aaa3 100644 --- a/Modules/AppLauncher/AppLauncher.qml +++ b/Modules/AppLauncher/AppLauncher.qml @@ -11,7 +11,6 @@ import qs.Services import qs.Widgets import "../../Helpers/FuzzySort.js" as Fuzzysort -import "../../Helpers/MathHelper.js" as MathHelper NLoader { id: appLauncher @@ -188,26 +187,54 @@ NLoader { // Handle calculator if (query.startsWith(">calc")) { var expr = searchText.slice(5).trim() - if (expr && isMathExpression(expr)) { - var value = safeEval(expr) - if (value !== null && value !== undefined && value !== "") { - var formattedResult = MathHelper.MathHelper.formatResult(value) + if (expr && expr !== "") { + try { + // Simple evaluation - only allow basic math operations + var sanitizedExpr = expr.replace(/[^0-9+\-*/().\s]/g, '') + var result = eval(sanitizedExpr) + + if (isFinite(result) && !isNaN(result)) { + var displayResult = Number.isInteger(result) ? result.toString() : result.toFixed(6).replace(/\.?0+$/, '') + results.push({ + "isCalculator": true, + "name": `${expr} = ${displayResult}`, + "result": result, + "expr": expr, + "icon": "calculate", + "execute": function () { + Quickshell.clipboardText = displayResult + copyText(displayResult) + Quickshell.execDetached(["notify-send", "Calculator", `${expr} = ${displayResult} (copied to clipboard)`]) + } + }) + } else { + results.push({ + "isCalculator": true, + "name": "Invalid expression", + "content": "Please enter a valid mathematical expression", + "icon": "calculate", + "execute": function () {} + }) + } + } catch (error) { results.push({ - "isCalculator": true, - "name": `Calculator: ${expr} = ${formattedResult}`, - "result": value, - "expr": expr, - "icon": "calculate", - "execute": function () { - Quickshell.clipboardText = String(formattedResult) - clipboardTextCopyProcess.copyText(String(formattedResult)) - Quickshell.execDetached( - ["notify-send", "Calculator Result", `${expr} = ${formattedResult} (copied to clipboard)`]) - } - }) + "isCalculator": true, + "name": "Invalid expression", + "content": "Please enter a valid mathematical expression", + "icon": "calculate", + "execute": function () {} + }) } + } else { + // Show placeholder when just ">calc" is entered + results.push({ + "isCalculator": true, + "name": "Calculator", + "content": "Enter a mathematical expression (e.g., 5+5, 2*3, 10/2)", + "icon": "calculate", + "execute": function () {} + }) } - return results } @@ -240,14 +267,7 @@ NLoader { updateClipboardHistory() } - function isMathExpression(str) { - // Allow more characters for enhanced math functions - return /^[-+*/().0-9\s\w]+$/.test(str) - } - function safeEval(expr) { - return MathHelper.MathHelper.evaluate(expr) - } // Main content container Rectangle { diff --git a/Modules/LockScreen/LockScreen.qml b/Modules/LockScreen/LockScreen.qml index eea1b5f..5d0df3e 100644 --- a/Modules/LockScreen/LockScreen.qml +++ b/Modules/LockScreen/LockScreen.qml @@ -551,9 +551,8 @@ WlSessionLock { height: 20 * scaling color: Color.mPrimary visible: passwordInput.activeFocus - anchors.left: asterisksText.right - anchors.leftMargin: Style.marginTiniest * scaling - anchors.verticalCenter: asterisksText.verticalCenter + Layout.leftMargin: asterisksText.width + Style.marginTiniest * scaling + Layout.alignment: Qt.AlignVCenter SequentialAnimation on opacity { loops: Animation.Infinite @@ -619,7 +618,7 @@ WlSessionLock { onClicked: lock.unlockAttempt() SequentialAnimation on scale { - running: containsMouse + running: executeButtonArea.containsMouse NumberAnimation { to: 1.05 duration: Style.animationFast @@ -628,7 +627,7 @@ WlSessionLock { } SequentialAnimation on scale { - running: !containsMouse + running: !executeButtonArea.containsMouse NumberAnimation { to: 1.0 duration: Style.animationFast diff --git a/README.md b/README.md index 044801c..73aae67 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,8 @@ A sleek, minimal, and thoughtfully crafted desktop shell for Wayland using **Qui - `matugen` - Material You color scheme generation - `cava` - Audio visualizer component - `gpu-screen-recorder` - Screen recording functionality +- `brightnessctl` - For internal/laptop monitor brightness +- `ddcutil` - For desktop monitor brightness --- @@ -119,7 +121,9 @@ qs ipc call lockScreen toggle ### Configuration -Access settings through the side panel (top right button) to configure weather, wallpapers, screen recording, audio, network, and theme options. +Access settings through the side panel (top right button) to configure weather, wallpapers, screen recording, audio, network, and theme options. +Configuration is usually stored in ~/.config/noctalia +If you upgrade from v1, you can delete the old configuration folder at ~/.config/Noctalia (with capital N) ### Application Launcher @@ -218,10 +222,11 @@ Noctalia/ ### Contributing -1. Follow the existing code style and patterns -2. Use the modular architecture for new features -3. Implement proper error handling and logging -4. Test with both Hyprland and Niri compositors (if applicable) +1. All Pull requests should be based on the "dev" branch +2. Follow the existing code style and patterns +3. Use the modular architecture for new features +4. Implement proper error handling and logging +5. Test with both Hyprland and Niri compositors (if applicable) Contributions are welcome! Don't worry about being perfect - every contribution helps! Whether it's fixing a small bug, adding a new feature, or improving documentation, we welcome all contributions. Feel free to open an issue to discuss ideas or ask questions before diving in. For feature requests and ideas, you can also use our discussions page.