add crypto
This commit is contained in:
parent
90cbe489f6
commit
af6a3bce3e
120 changed files with 24616 additions and 462 deletions
|
|
@ -0,0 +1,262 @@
|
|||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import Qt5Compat.GraphicalEffects
|
||||
import "root:/Data" as Data
|
||||
|
||||
// Authentication area
|
||||
Column {
|
||||
id: authColumn
|
||||
anchors.centerIn: parent
|
||||
anchors.verticalCenterOffset: 80
|
||||
spacing: 20
|
||||
width: 300
|
||||
|
||||
required property bool isVisible
|
||||
required property string errorMessage
|
||||
required property bool isAuthenticating
|
||||
required property bool authSuccess
|
||||
required property string usernameText
|
||||
|
||||
signal passwordEntered(string password)
|
||||
|
||||
// Expose password field
|
||||
readonly property alias passwordField: passwordField
|
||||
|
||||
// Subtle slide up animation (after main slide)
|
||||
transform: Translate {
|
||||
id: authTransform
|
||||
y: isVisible ? 0 : 50
|
||||
Behavior on y {
|
||||
SequentialAnimation {
|
||||
PauseAnimation { duration: 600 } // Wait for main slide and time
|
||||
NumberAnimation {
|
||||
duration: 600
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
opacity: isVisible ? 1.0 : 0.0
|
||||
Behavior on opacity {
|
||||
SequentialAnimation {
|
||||
PauseAnimation { duration: 700 } // Wait for time to appear
|
||||
NumberAnimation {
|
||||
duration: 600
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// User avatar with circular masking
|
||||
Rectangle {
|
||||
id: avatarContainer
|
||||
width: 100
|
||||
height: 100
|
||||
radius: 50
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
color: "transparent"
|
||||
border.color: Data.ThemeManager.accentColor
|
||||
border.width: 4
|
||||
clip: true
|
||||
|
||||
// Scale animation for avatar
|
||||
scale: isVisible ? 1.0 : 0.0
|
||||
Behavior on scale {
|
||||
SequentialAnimation {
|
||||
PauseAnimation { duration: 1000 } // Wait for auth area to appear
|
||||
NumberAnimation {
|
||||
duration: 400
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: avatarImage
|
||||
anchors.fill: parent
|
||||
anchors.margins: 4
|
||||
source: Data.Settings.avatarSource
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
cache: false
|
||||
visible: false // Hidden for masking
|
||||
asynchronous: true
|
||||
sourceSize.width: 92
|
||||
sourceSize.height: 92
|
||||
}
|
||||
|
||||
// Apply circular mask to avatar
|
||||
OpacityMask {
|
||||
anchors.fill: avatarImage
|
||||
source: avatarImage
|
||||
maskSource: Rectangle {
|
||||
width: avatarImage.width
|
||||
height: avatarImage.height
|
||||
radius: 46
|
||||
visible: false
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback icon if avatar fails to load
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: "person"
|
||||
font.family: "Material Symbols Outlined"
|
||||
font.pixelSize: 48
|
||||
color: Data.ThemeManager.accentColor
|
||||
visible: avatarImage.status !== Image.Ready
|
||||
}
|
||||
}
|
||||
|
||||
// Username display
|
||||
Text {
|
||||
id: usernameDisplay
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
font.family: "FiraCode Nerd Font"
|
||||
font.pixelSize: 18
|
||||
color: Data.ThemeManager.primaryText
|
||||
text: usernameText
|
||||
}
|
||||
|
||||
// Password input field
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: 25
|
||||
color: Data.ThemeManager.withOpacity(Data.ThemeManager.bgLighter, 0.4)
|
||||
border.color: passwordField.activeFocus ? Data.ThemeManager.accentColor : Data.ThemeManager.withOpacity(Data.ThemeManager.border, 0.6)
|
||||
border.width: 2
|
||||
|
||||
TextInput {
|
||||
id: passwordField
|
||||
anchors.fill: parent
|
||||
anchors.margins: 15
|
||||
echoMode: TextInput.Normal
|
||||
font.family: "FiraCode Nerd Font"
|
||||
font.pixelSize: 16
|
||||
color: "transparent" // Hide the actual text
|
||||
selectionColor: Data.ThemeManager.accentColor
|
||||
selectByMouse: true
|
||||
focus: isVisible
|
||||
|
||||
onAccepted: {
|
||||
if (text.length > 0) {
|
||||
passwordEntered(text)
|
||||
}
|
||||
}
|
||||
|
||||
// Password mask with better spaced dots
|
||||
Row {
|
||||
id: passwordDotsRow
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
spacing: 8
|
||||
visible: passwordField.text.length > 0
|
||||
|
||||
property int previousLength: 0
|
||||
|
||||
Repeater {
|
||||
id: passwordRepeater
|
||||
model: passwordField.text.length
|
||||
delegate: Rectangle {
|
||||
id: passwordDot
|
||||
width: 8
|
||||
height: 8
|
||||
radius: 4
|
||||
color: Data.ThemeManager.primaryText
|
||||
|
||||
property bool isNewDot: index >= passwordDotsRow.previousLength
|
||||
|
||||
// Only animate new dots, existing ones stay visible
|
||||
scale: isNewDot ? 0 : 1.0
|
||||
opacity: isNewDot ? 0 : 1.0
|
||||
|
||||
ParallelAnimation {
|
||||
running: passwordDot.isNewDot
|
||||
|
||||
NumberAnimation {
|
||||
target: passwordDot
|
||||
property: "scale"
|
||||
from: 0
|
||||
to: 1.0
|
||||
duration: 200
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
|
||||
NumberAnimation {
|
||||
target: passwordDot
|
||||
property: "opacity"
|
||||
from: 0
|
||||
to: 1.0
|
||||
duration: 150
|
||||
easing.type: Easing.OutQuad
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Track length changes to identify new dots
|
||||
Connections {
|
||||
target: passwordField
|
||||
function onTextChanged() {
|
||||
// Update previous length after a short delay to allow new dots to be marked as new
|
||||
Qt.callLater(function() {
|
||||
passwordDotsRow.previousLength = passwordField.text.length
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Placeholder text
|
||||
Text {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
text: "Password"
|
||||
font.family: passwordField.font.family
|
||||
font.pixelSize: passwordField.font.pixelSize
|
||||
color: Data.ThemeManager.withOpacity(Data.ThemeManager.secondaryText, 0.7)
|
||||
visible: passwordField.text.length === 0 && !passwordField.activeFocus
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Error message
|
||||
Text {
|
||||
id: errorText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
font.family: "FiraCode Nerd Font"
|
||||
font.pixelSize: 14
|
||||
color: Data.ThemeManager.errorColor
|
||||
text: errorMessage
|
||||
visible: errorMessage !== ""
|
||||
wrapMode: Text.WordWrap
|
||||
width: parent.width
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
// Authentication status
|
||||
Text {
|
||||
id: statusText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
font.family: "FiraCode Nerd Font"
|
||||
font.pixelSize: 14
|
||||
color: authSuccess ? Data.ThemeManager.success : Data.ThemeManager.accentColorBright
|
||||
text: {
|
||||
if (authSuccess) return "Authentication successful!"
|
||||
if (isAuthenticating) return "Authenticating..."
|
||||
return ""
|
||||
}
|
||||
visible: isAuthenticating || authSuccess
|
||||
}
|
||||
|
||||
// Public function to clear password
|
||||
function clearPassword() {
|
||||
passwordField.text = ""
|
||||
passwordField.focus = true
|
||||
}
|
||||
|
||||
// Public function to focus password field
|
||||
function focusPassword() {
|
||||
passwordField.focus = true
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue