- Move the ~17 top-level QML files into views/, settings/, and forms/ subdirectories, grouped so cross-directory type references stay minimal (only 3 files need an added `import` line). Root now only holds the four surfaces plugin.json points at directly. - Add a `dms ipc call dankChat popout` IPC target to open the floating window directly, alongside the existing `toggle`, and document both in the README along with the new directory layout. - Add one line of breathing room between the last message and the composer bar via the message ListView's bottomMargin (measured with FontMetrics rather than a guessed pixel value). Co-Authored-By: Claude Sonnet 5 <[email protected]>
84 lines
2.9 KiB
QML
84 lines
2.9 KiB
QML
import QtQuick
|
|
import QtQuick.Layouts
|
|
import qs.Common
|
|
import qs.Widgets
|
|
|
|
// Discord has no username/password path here by design (see the project
|
|
// plan's Discord milestone) - the QR flow is Discord's own official
|
|
// cross-device login (the same one discord.com/app's "Log in with QR Code"
|
|
// offers), just driven from chatd instead of a browser. chatd does all the
|
|
// protocol work (backend/discord.rs) and pushes progress back as events;
|
|
// this form only ever needs to request a login and render whatever it's
|
|
// told to render (QR image / status text) - see ChatView.qml's
|
|
// discordLoginQr/discordLoginScanned/discordLoginResult handling.
|
|
ColumnLayout {
|
|
id: root
|
|
|
|
signal connectRequested()
|
|
|
|
property string qrPath: ""
|
|
property string statusText: ""
|
|
property bool pending: false
|
|
|
|
// The QML property-binding-vs-assignment rule bites here: `pending` is
|
|
// only ever *assigned* (never externally bound) so this component can
|
|
// freely clear it itself once anything comes back - a bound property
|
|
// would get permanently detached from its binding the instant this
|
|
// component's own onClicked assigned to it.
|
|
onQrPathChanged: root.pending = false
|
|
onStatusTextChanged: root.pending = false
|
|
|
|
spacing: Theme.spacingXS
|
|
|
|
StyledText {
|
|
Layout.fillWidth: true
|
|
text: "Log in the same way the Discord app's own \"Log in with QR Code\" does: open Discord on your phone, go to Settings → Scan QR Code, and point it at the code below."
|
|
wrapMode: Text.WordWrap
|
|
color: Theme.surfaceVariantText
|
|
}
|
|
|
|
DankButton {
|
|
text: root.pending ? "Generating..." : (root.qrPath ? "Show a new QR code" : "Show QR code")
|
|
enabled: !root.pending
|
|
onClicked: {
|
|
root.pending = true;
|
|
root.qrPath = "";
|
|
root.statusText = "";
|
|
root.connectRequested();
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
Layout.preferredWidth: 220
|
|
Layout.preferredHeight: 220
|
|
Layout.alignment: Qt.AlignHCenter
|
|
Layout.topMargin: Theme.spacingS
|
|
visible: root.qrPath !== ""
|
|
color: "white"
|
|
radius: Theme.cornerRadius
|
|
|
|
Image {
|
|
anchors.fill: parent
|
|
anchors.margins: Theme.spacingM
|
|
// chatd renders the QR code to a temp PNG and hands back a
|
|
// plain filesystem path (see backend/discord.rs) rather than
|
|
// embedding it as a base64 data URI in the event - keeps every
|
|
// line on the JSON-RPC socket small.
|
|
source: root.qrPath ? "file://" + root.qrPath : ""
|
|
fillMode: Image.PreserveAspectFit
|
|
smooth: false
|
|
cache: false
|
|
}
|
|
}
|
|
|
|
StyledText {
|
|
Layout.fillWidth: true
|
|
Layout.topMargin: Theme.spacingXS
|
|
visible: root.statusText !== ""
|
|
text: root.statusText
|
|
wrapMode: Text.WordWrap
|
|
horizontalAlignment: Text.AlignHCenter
|
|
color: Theme.surfaceVariantText
|
|
}
|
|
}
|