add crypto

This commit is contained in:
zack 2025-07-22 20:21:21 -04:00
parent 90cbe489f6
commit af6a3bce3e
Signed by: zoey
GPG key ID: 81FB9FECDD6A33E2
120 changed files with 24616 additions and 462 deletions

View file

@ -0,0 +1,98 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import "root:/Data" as Data
// Dual-button notification and clipboard history toggle bar
Rectangle {
id: root
width: 42
color: Qt.darker(Data.ThemeManager.bgColor, 1.15)
radius: 12
z: 2 // Above notification history overlay
required property bool notificationHistoryVisible
required property bool clipboardHistoryVisible
required property var notificationHistory
signal notificationToggleRequested()
signal clipboardToggleRequested()
// Combined hover state for parent component tracking
property bool containsMouse: notifButtonMouseArea.containsMouse || clipButtonMouseArea.containsMouse
property real buttonHeight: 38
height: buttonHeight * 2 + 4 // Two buttons with spacing
Item {
anchors.fill: parent
anchors.margins: 2
// Notifications toggle button (top half)
Rectangle {
id: notificationPill
anchors {
top: parent.top
left: parent.left
right: parent.right
bottom: parent.verticalCenter
bottomMargin: 2 // Half of button spacing
}
radius: 12
color: notifButtonMouseArea.containsMouse || root.notificationHistoryVisible ?
Qt.rgba(Data.ThemeManager.accentColor.r, Data.ThemeManager.accentColor.g, Data.ThemeManager.accentColor.b, 0.2) :
Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.05)
border.color: notifButtonMouseArea.containsMouse || root.notificationHistoryVisible ? Data.ThemeManager.accentColor : "transparent"
border.width: 1
MouseArea {
id: notifButtonMouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: root.notificationToggleRequested()
}
Label {
anchors.centerIn: parent
text: "notifications"
font.family: "Material Symbols Outlined"
font.pixelSize: 16
color: notifButtonMouseArea.containsMouse || root.notificationHistoryVisible ?
Data.ThemeManager.accentColor : Data.ThemeManager.fgColor
}
}
// Clipboard toggle button (bottom half)
Rectangle {
id: clipboardPill
anchors {
top: parent.verticalCenter
left: parent.left
right: parent.right
bottom: parent.bottom
topMargin: 2 // Half of button spacing
}
radius: 12
color: clipButtonMouseArea.containsMouse || root.clipboardHistoryVisible ?
Qt.rgba(Data.ThemeManager.accentColor.r, Data.ThemeManager.accentColor.g, Data.ThemeManager.accentColor.b, 0.2) :
Qt.rgba(Data.ThemeManager.fgColor.r, Data.ThemeManager.fgColor.g, Data.ThemeManager.fgColor.b, 0.05)
border.color: clipButtonMouseArea.containsMouse || root.clipboardHistoryVisible ? Data.ThemeManager.accentColor : "transparent"
border.width: 1
MouseArea {
id: clipButtonMouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: root.clipboardToggleRequested()
}
Label {
anchors.centerIn: parent
text: "content_paste"
font.family: "Material Symbols Outlined"
font.pixelSize: 16
color: clipButtonMouseArea.containsMouse || root.clipboardHistoryVisible ?
Data.ThemeManager.accentColor : Data.ThemeManager.fgColor
}
}
}
}

View file

@ -0,0 +1,52 @@
import QtQuick
// Top-edge hover trigger
Rectangle {
id: root
width: 360
height: 1
color: "red"
anchors.top: parent.top
signal triggered()
// Hover detection area at screen top edge
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
property bool isHovered: containsMouse
// Timer coordination
onIsHoveredChanged: {
if (isHovered) {
showTimer.start()
hideTimer.stop()
} else {
hideTimer.start()
showTimer.stop()
}
}
onEntered: hideTimer.stop()
}
// Delayed show trigger to prevent accidental activation
Timer {
id: showTimer
interval: 200
onTriggered: root.triggered()
}
// Hide delay timer (controlled by parent)
Timer {
id: hideTimer
interval: 500
}
// Public interface
readonly property alias containsMouse: mouseArea.containsMouse
function stopHideTimer() { hideTimer.stop() }
function startHideTimer() { hideTimer.start() }
}

View file

@ -0,0 +1,226 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import "root:/Data" as Data
// System tray context menu
Rectangle {
id: root
width: parent.width
height: visible ? calculatedHeight : 0
visible: false
enabled: visible
clip: true
color: Data.ThemeManager.bgColor
border.color: Data.ThemeManager.accentColor
border.width: 2
radius: 20
required property var menu
required property var systemTrayY
required property var systemTrayHeight
property bool containsMouse: trayMenuMouseArea.containsMouse
property bool menuJustOpened: false
property point triggerPoint: Qt.point(0, 0)
property Item originalParent
property int totalCount: opener.children ? opener.children.values.length : 0
signal hideRequested()
MouseArea {
id: trayMenuMouseArea
anchors.fill: parent
hoverEnabled: true
preventStealing: true
propagateComposedEvents: false
}
onVisibleChanged: {
if (visible) {
menuJustOpened = true
Qt.callLater(function() {
menuJustOpened = false
})
}
}
function toggle() {
visible = !visible
if (visible) {
menuJustOpened = true
Qt.callLater(function() {
menuJustOpened = false
})
}
}
function show(point, parentItem) {
visible = true
menuJustOpened = true
Qt.callLater(function() {
menuJustOpened = false
})
}
function hide() {
visible = false
menuJustOpened = false
// Small delay before notifying hide to prevent control panel flicker
Qt.callLater(function() {
hideRequested()
})
}
// Smart positioning to avoid screen edges
y: {
var preferredY = systemTrayY + systemTrayHeight + 10
var availableSpace = parent.height - preferredY - 20
if (calculatedHeight > availableSpace) {
return systemTrayY - height - 10
}
return preferredY
}
Behavior on height {
NumberAnimation { duration: 200; easing.type: Easing.OutCubic }
}
// Dynamic height calculation based on menu item count and types
property int calculatedHeight: {
if (totalCount === 0) return 40
var separatorCount = 0
var regularItemCount = 0
if (opener.children && opener.children.values) {
for (var i = 0; i < opener.children.values.length; i++) {
if (opener.children.values[i].isSeparator) {
separatorCount++
} else {
regularItemCount++
}
}
}
// Calculate total height: separators + grid rows + margins
var separatorHeight = separatorCount * 12
var regularItemRows = Math.ceil(regularItemCount / 2)
var regularItemHeight = regularItemRows * 32
return Math.max(80, 35 + separatorHeight + regularItemHeight + 40)
}
// Menu opener handles the native menu integration
QsMenuOpener {
id: opener
menu: root.menu
}
// Grid layout for menu items (2 columns)
GridView {
id: gridView
anchors.fill: parent
anchors.margins: 20
cellWidth: width / 2
cellHeight: 32
interactive: false
flow: GridView.FlowLeftToRight
layoutDirection: Qt.LeftToRight
model: ScriptModel {
values: opener.children ? [...opener.children.values] : []
}
delegate: Item {
id: entry
required property var modelData
required property int index
width: gridView.cellWidth - 4
height: modelData.isSeparator ? 12 : 30
// Separator line
Rectangle {
anchors.fill: parent
anchors.leftMargin: 8
anchors.rightMargin: 8
anchors.topMargin: 4
anchors.bottomMargin: 4
visible: modelData.isSeparator
color: "transparent"
Rectangle {
anchors.centerIn: parent
width: parent.width * 0.8
height: 1
color: Qt.darker(Data.ThemeManager.accentColor, 1.5)
opacity: 0.6
}
}
// Regular menu item
Rectangle {
id: itemBackground
anchors.fill: parent
anchors.margins: 2
visible: !modelData.isSeparator
color: "transparent"
radius: 6
RowLayout {
anchors.fill: parent
anchors.leftMargin: 8
anchors.rightMargin: 8
spacing: 6
Image {
Layout.preferredWidth: 16
Layout.preferredHeight: 16
source: modelData?.icon ?? ""
visible: (modelData?.icon ?? "") !== ""
fillMode: Image.PreserveAspectFit
}
Text {
Layout.fillWidth: true
color: mouseArea.containsMouse ? Data.ThemeManager.accentColor : Data.ThemeManager.fgColor
text: modelData?.text ?? ""
font.pixelSize: 11
font.family: "Roboto"
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
maximumLineCount: 1
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
enabled: (modelData?.enabled ?? true) && root.visible && !modelData.isSeparator
onEntered: itemBackground.color = Qt.rgba(Data.ThemeManager.accentColor.r, Data.ThemeManager.accentColor.g, Data.ThemeManager.accentColor.b, 0.15)
onExited: itemBackground.color = "transparent"
onClicked: {
modelData.triggered()
root.hide()
}
}
}
}
}
// Empty state indicator
Item {
anchors.centerIn: gridView
visible: gridView.count === 0
Label {
anchors.centerIn: parent
text: "No tray items available"
color: Qt.darker(Data.ThemeManager.fgColor, 2)
font.pixelSize: 14
font.family: "Roboto"
}
}
}

View file

@ -0,0 +1,149 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import "root:/Data" as Data
// Wallpaper selector grid
Item {
id: root
property bool isVisible: false
signal visibilityChanged(bool visible)
// Use all space provided by parent
anchors.fill: parent
visible: isVisible
enabled: visible
clip: true
property bool containsMouse: wallpaperSelectorMouseArea.containsMouse || scrollView.containsMouse
property bool menuJustOpened: false
// Hover state management for auto-hide functionality
onContainsMouseChanged: {
if (containsMouse) {
hideTimer.stop()
} else if (!menuJustOpened && !isVisible) {
hideTimer.restart()
}
}
onVisibleChanged: {
if (visible) {
menuJustOpened = true
hideTimer.stop()
Qt.callLater(function() {
menuJustOpened = false
})
}
}
MouseArea {
id: wallpaperSelectorMouseArea
anchors.fill: parent
hoverEnabled: true
preventStealing: false
propagateComposedEvents: true
}
// Scrollable wallpaper grid with memory-conscious loading
ScrollView {
id: scrollView
anchors.fill: parent
clip: true
property bool containsMouse: gridMouseArea.containsMouse
MouseArea {
id: gridMouseArea
anchors.fill: parent
hoverEnabled: true
propagateComposedEvents: true
}
GridView {
id: wallpaperGrid
anchors.fill: parent
cellWidth: parent.width / 2 - 8 // 2-column layout with spacing
cellHeight: cellWidth * 0.6 // Wallpaper aspect ratio
model: Data.WallpaperManager.wallpaperList
cacheBuffer: 0 // Memory optimization - no cache buffer
leftMargin: 4
rightMargin: 4
topMargin: 4
bottomMargin: 4
delegate: Item {
width: wallpaperGrid.cellWidth - 8
height: wallpaperGrid.cellHeight - 8
Rectangle {
id: wallpaperItem
anchors.fill: parent
anchors.margins: 4
color: Qt.darker(Data.ThemeManager.bgColor, 1.2)
radius: 20
Behavior on scale {
NumberAnimation { duration: 150; easing.type: Easing.OutCubic }
}
// Wallpaper preview image with viewport-based loading
Image {
id: wallpaperImage
anchors.fill: parent
anchors.margins: 4
source: modelData
fillMode: Image.PreserveAspectCrop
asynchronous: true
cache: false // Memory optimization - no image caching
sourceSize.width: Math.min(width, 150) // Reduced resolution for memory
sourceSize.height: Math.min(height, 90)
// Only load when visible in viewport - major memory optimization
visible: parent.parent.y >= wallpaperGrid.contentY - parent.parent.height &&
parent.parent.y <= wallpaperGrid.contentY + wallpaperGrid.height
// Layer effects disabled for memory savings
// layer.enabled: true
// layer.effect: OpacityMask {
// maskSource: Rectangle {
// width: wallpaperImage.width
// height: wallpaperImage.height
// radius: 18
// }
// }
}
// Current wallpaper selection indicator
Rectangle {
visible: modelData === Data.WallpaperManager.currentWallpaper
anchors.fill: parent
radius: parent.radius
color: "transparent"
border.color: Data.ThemeManager.accentColor
border.width: 2
}
// Hover and click handling
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: wallpaperItem.scale = 1.05
onExited: wallpaperItem.scale = 1.0
onClicked: {
Data.WallpaperManager.setWallpaper(modelData)
// Stays in wallpaper tab after selection
}
}
}
}
}
}
Component.onCompleted: {
// Use lazy loading to only load wallpapers when this component is actually used
Data.WallpaperManager.ensureWallpapersLoaded()
}
}