Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 0 additions & 9 deletions src/app/modules/keycard_channel/constants.nim

This file was deleted.

2 changes: 0 additions & 2 deletions src/app/modules/keycard_channel/module.nim
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@ import nimqml
import io_interface, view, controller
import app/global/global_singleton
import app/core/eventemitter
import ./constants

export io_interface
export constants

type
Module* = ref object of io_interface.AccessInterface
Expand Down
23 changes: 0 additions & 23 deletions src/app/modules/keycard_channel/view.nim
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import nimqml

import ./io_interface
import ./constants

QtObject:
type
Expand All @@ -14,7 +13,6 @@ QtObject:
proc newView*(delegate: io_interface.AccessInterface): View =
new(result, delete)
result.delegate = delegate
result.keycardChannelState = KEYCARD_CHANNEL_STATE_IDLE
result.setup()

proc load*(self: View) =
Expand All @@ -33,27 +31,6 @@ QtObject:
write = setKeycardChannelState
notify = keycardChannelStateChanged

# Constants for channel states (readonly properties for QML)
proc getStateIdle*(self: View): string {.slot.} =
return KEYCARD_CHANNEL_STATE_IDLE
QtProperty[string] stateIdle:
read = getStateIdle

proc getStateWaitingForKeycard*(self: View): string {.slot.} =
return KEYCARD_CHANNEL_STATE_WAITING_FOR_KEYCARD
QtProperty[string] stateWaitingForKeycard:
read = getStateWaitingForKeycard

proc getStateReading*(self: View): string {.slot.} =
return KEYCARD_CHANNEL_STATE_READING
QtProperty[string] stateReading:
read = getStateReading

proc getStateError*(self: View): string {.slot.} =
return KEYCARD_CHANNEL_STATE_ERROR
QtProperty[string] stateError:
read = getStateError

proc setup(self: View) =
self.QObject.setup

Expand Down
222 changes: 222 additions & 0 deletions storybook/pages/KeycardChannelDrawerPage.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts

import Storybook

import StatusQ.Core
import StatusQ.Core.Theme
import StatusQ.Controls
import StatusQ.Components

import shared.popups

SplitView {
id: root

orientation: Qt.Horizontal

Logs { id: logs }

// Helper timers for test scenarios
Timer {
id: timer1
interval: 1500
onTriggered: {
if (root.currentScenario === "success") {
logs.logEvent("Changing to reading state")
stateCombo.currentIndex = 2 // reading
timer2.start()
} else if (root.currentScenario === "error") {
logs.logEvent("Changing to reading state")
stateCombo.currentIndex = 2 // reading
timer2.start()
} else if (root.currentScenario === "quick") {
logs.logEvent("Quick change to reading")
stateCombo.currentIndex = 2 // reading
timer2.start()
}
}
}

Timer {
id: timer2
interval: root.currentScenario === "quick" ? 300 : 1500
onTriggered: {
if (root.currentScenario === "success") {
logs.logEvent("Changing to idle state (success)")
stateCombo.currentIndex = 0 // idle (will trigger success)
} else if (root.currentScenario === "error") {
logs.logEvent("Changing to error state")
stateCombo.currentIndex = 3 // error
} else if (root.currentScenario === "quick") {
logs.logEvent("Quick change to idle (success)")
stateCombo.currentIndex = 0 // idle
}
root.currentScenario = ""
}
}

property string currentScenario: ""

Item {
SplitView.fillWidth: true
SplitView.fillHeight: true

KeycardChannelDrawer {
id: drawer

currentState: stateCombo.currentValue
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside

onDismissed: {
logs.logEvent("KeycardChannelDrawer::dismissed()")
}
}
}

LogsAndControlsPanel {
id: logsAndControlsPanel

SplitView.preferredWidth: 350
SplitView.fillHeight: true

logsView.logText: logs.logText

ColumnLayout {
Layout.fillWidth: true
spacing: Theme.padding

// State control section
RowLayout {
Layout.fillWidth: true
spacing: Theme.halfPadding

Label {
Layout.preferredWidth: 120
text: "Current state:"
}

ComboBox {
id: stateCombo
Layout.fillWidth: true

textRole: "text"
valueRole: "value"

model: ListModel {
ListElement { text: "Idle"; value: "idle" }
ListElement { text: "Waiting for Keycard"; value: "waiting-for-keycard" }
ListElement { text: "Reading"; value: "reading" }
ListElement { text: "Error"; value: "error" }
}

currentIndex: 0
}
}

// State info display
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: infoColumn.implicitHeight + Theme.padding * 2
color: Theme.palette.baseColor5
radius: Theme.radius
border.width: 1
border.color: Theme.palette.baseColor2

ColumnLayout {
id: infoColumn
anchors.fill: parent
anchors.margins: Theme.padding
spacing: Theme.halfPadding

StatusBaseText {
Layout.fillWidth: true
text: "State Information"
font.bold: true
font.pixelSize: Theme.primaryTextFontSize
}

StatusBaseText {
Layout.fillWidth: true
text: "Current: %1".arg(stateCombo.currentText)
font.pixelSize: Theme.tertiaryTextFontSize
color: Theme.palette.baseColor1
}

StatusBaseText {
Layout.fillWidth: true
text: "Opened: %1".arg(drawer.opened ? "Yes" : "No")
font.pixelSize: Theme.tertiaryTextFontSize
color: Theme.palette.baseColor1
}
}
}

// Scenario buttons section
Label {
Layout.fillWidth: true
Layout.topMargin: Theme.padding
text: "Test Scenarios:"
font.bold: true
}

Button {
Layout.fillWidth: true
text: "Simulate Success Flow"
onClicked: {
logs.logEvent("Starting success flow simulation")
root.currentScenario = "success"
stateCombo.currentIndex = 1 // waiting-for-keycard
timer1.start()
}
}

Button {
Layout.fillWidth: true
text: "Simulate Error Flow"
onClicked: {
logs.logEvent("Starting error flow simulation")
root.currentScenario = "error"
stateCombo.currentIndex = 1 // waiting-for-keycard
timer1.start()
}
}

Button {
Layout.fillWidth: true
text: "Simulate Quick State Changes"
onClicked: {
logs.logEvent("Testing state queue with rapid changes")
root.currentScenario = "quick"
stateCombo.currentIndex = 1 // waiting-for-keycard
timer1.interval = 300
timer1.start()
}
}

Button {
Layout.fillWidth: true
text: "Open Drawer Manually"
onClicked: {
logs.logEvent("Manually opening drawer")
drawer.open()
}
}

Button {
Layout.fillWidth: true
text: "Clear Logs"
onClicked: logs.clear()
}

Item {
Layout.fillHeight: true
}
}
}
}

// category: Popups
// status: good

22 changes: 17 additions & 5 deletions ui/StatusQ/src/StatusQ/Controls/StatusPinInput.qml
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,13 @@ Item {
*/
property int additionalSpacing: 0

/*!
\qmlproperty flags StatusPinInput::inputMethodHints
This property allows you to customize the input method hints for the virtual keyboard.
The default value is Qt.ImhNone which allows any input based on the validator.
*/
property int inputMethodHints: Qt.ImhNone

signal pinEditedManually()

QtObject {
Expand Down Expand Up @@ -158,9 +165,10 @@ Item {
Convenient method to force active focus in case it gets stolen by any other component.
*/
function forceFocus() {
if (Utils.isMobile)
return
inputText.forceActiveFocus()
if (Qt.inputMethod.visible == false) {
Qt.inputMethod.show()
}
d.activateBlink()
}

Expand Down Expand Up @@ -208,10 +216,14 @@ Item {
TextInput {
id: inputText
objectName: "pinInputTextInput"
visible: false
focus: !Utils.isMobile
visible: true
// Set explicit dimensions for Android keyboard input to work
width: 1
height: 1
opacity: 0
maximumLength: root.pinLen
validator: d.statusValidator.validatorObj
inputMethodHints: root.inputMethodHints
// validator: d.statusValidator.validatorObj
onTextChanged: {
// Modify state of current introduced character position:
if(text.length >= (d.currentPinIndex + 1)) {
Expand Down
7 changes: 7 additions & 0 deletions ui/app/AppLayouts/Onboarding/components/LoginKeycardBox.qml
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ Control {
objectName: "pinInput"
validator: StatusIntValidator { bottom: 0; top: 999999 }
visible: false
inputMethodHints: Qt.ImhDigitsOnly

onPinInputChanged: {
if (pinInput.length === 6) {
Expand Down Expand Up @@ -235,6 +236,7 @@ Control {
PropertyChanges {
target: pinInputField
visible: true
focus: true
}
PropertyChanges {
target: background
Expand All @@ -251,4 +253,9 @@ Control {
}
}
]

TapHandler {
enabled: pinInputField.visible
onTapped: pinInputField.forceFocus()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ KeycardBasePage {
anchors.horizontalCenter: parent.horizontalCenter
pinLen: Constants.keycard.general.keycardPinLength
validator: StatusIntValidator { bottom: 0; top: 999999 }
inputMethodHints: Qt.ImhDigitsOnly
onPinInputChanged: {
if (pinInput.pinInput.length === pinInput.pinLen) {
root.authorizationRequested(pinInput.pinInput)
Expand Down
Loading