Files
qbz/crates/qbz-qt/qml/Main.qml
T
vicrodh 9a4fec6b70 refactor(qbz-qt): phase 23 part 1 — QML module layout + first five domain bridges
Two fronts of the modularization, both gated green before this commit.

QML leaves the flat qml/ directory for seven modules: cards, controls,
rows, settings, shell, theme, views. Only Main.qml and LoginScreen.qml
stay at the root. build.rs matches the tree exactly (55 files), relative
imports and asset paths were re-anchored for the new depth.

The QbzBridge God-object starts breaking up: QbzSession, QbzShell,
QbzPlayer, QbzQueue and QbzHome are now their own #[cxx_qt::bridge]
singletons, each with its own OnceLock<CxxQtThread> and ui() hop, booted
in order from Main.qml. Bridge files stay directly under src/ because
cxx-qt-build only accepts rust_files from one directory (QTBUG-93443).

bridge.rs keeps 5.5 domains (library, album/artist, settings,
integrations, search, playlist) and dies once they are split out.

cc
2026-07-28 11:08:20 -06:00

185 lines
6.9 KiB
QML

// Root window: dark background + a Loader keyed on the bridge's `screen`
// property ("splash" | "login" | "shell"). Kicks off the Rust boot
// sequence once the QML tree is complete (the bridge registers its Qt
// thread handle in that first invokable, so every async UI hop lands).
//
// Font: the Slint app bundles the Inter 18pt faces (app.slint); the same
// TTFs are embedded here via qrc and applied app-wide through the
// ApplicationWindow font (children inherit).
import QtQuick
import QtQuick.Controls
import com.blitzfc.qbz
import "theme"
ApplicationWindow {
id: window
width: 1280
height: 800
minimumWidth: 800
minimumHeight: 600
visible: true
title: "QBZ"
// Custom chrome (phase 7/12): frameless but OPAQUE — the phase-7
// translucent window was a misread: the Slint MAIN window keeps an
// OPAQUE swapchain (only the miniplayer blends; crates/qbz/src/main.rs
// set_surface_prefers_transparent + the Cargo.toml patch comment), and
// the rounded corners in the Slint screenshots come from the
// COMPOSITOR, not the app — app.slint's root is opaque surface-main
// with square corners and a square 1px hairline frame. The system
// titlebar is the `use_system_title_bar` pref (ui_prefs.json; applied
// at startup, restart semantics like Slint).
flags: QbzShell.systemTitleBar ? Qt.Window : (Qt.Window | Qt.FramelessWindowHint)
color: "#1a1a1a"
FontLoader { id: interRegular; source: "assets/fonts/Inter_18pt-Regular.ttf" }
FontLoader { id: interMedium; source: "assets/fonts/Inter_18pt-Medium.ttf" }
FontLoader { id: interSemiBold; source: "assets/fonts/Inter_18pt-SemiBold.ttf" }
FontLoader { id: interBold; source: "assets/fonts/Inter_18pt-Bold.ttf" }
font.family: interRegular.status === FontLoader.Ready ? interRegular.name : "Sans Serif"
// Phase 23: every domain singleton boots (registers its Qt-thread
// hop; QbzSession.boot additionally fires the app boot sequence).
Component.onCompleted: {
QbzSession.boot()
QbzShell.boot()
QbzPlayer.boot()
QbzQueue.boot()
QbzHome.boot()
QbzBridge.boot()
}
Loader {
id: screenLoader
anchors.fill: parent
active: QbzSession.screen !== "splash"
source: QbzSession.screen === "login"
? "LoginScreen.qml"
: (QbzSession.screen === "shell" ? "shell/AppShell.qml" : "")
// Hand the host window down for drag/maximize/resize (custom chrome).
onLoaded: if (screenLoader.item) screenLoader.item.hostWindow = window
}
// Frameless hairline (app.slint's no-frame 1px edge) — paints at the
// very rim, over everything. SQUARE (the app draws no corner rounding).
Rectangle {
anchors.fill: parent
color: "transparent"
border.width: 1
border.color: "#14ffffff"
visible: !QbzShell.systemTitleBar
&& window.visibility !== Window.Maximized && window.visibility !== Window.FullScreen
}
// Edge/corner resize grips (custom chrome — the compositor draws no
// border). 6px, invisible.
MouseArea {
anchors.left: parent.left; anchors.top: parent.top; anchors.bottom: parent.bottom; width: 6
cursorShape: Qt.SizeHorCursor
enabled: !QbzShell.systemTitleBar
onPressed: window.startSystemResize(Qt.LeftEdge)
}
MouseArea {
anchors.right: parent.right; anchors.top: parent.top; anchors.bottom: parent.bottom; width: 6
cursorShape: Qt.SizeHorCursor
enabled: !QbzShell.systemTitleBar
onPressed: window.startSystemResize(Qt.RightEdge)
}
MouseArea {
anchors.left: parent.left; anchors.right: parent.right; anchors.top: parent.top; height: 6
cursorShape: Qt.SizeVerCursor
enabled: !QbzShell.systemTitleBar
onPressed: window.startSystemResize(Qt.TopEdge)
}
MouseArea {
anchors.left: parent.left; anchors.right: parent.right; anchors.bottom: parent.bottom; height: 6
cursorShape: Qt.SizeVerCursor
enabled: !QbzShell.systemTitleBar
onPressed: window.startSystemResize(Qt.BottomEdge)
}
MouseArea {
anchors.left: parent.left; anchors.top: parent.top; width: 12; height: 12
cursorShape: Qt.SizeFDiagCursor
enabled: !QbzShell.systemTitleBar
onPressed: window.startSystemResize(Qt.TopEdge | Qt.LeftEdge)
}
MouseArea {
anchors.right: parent.right; anchors.top: parent.top; width: 12; height: 12
cursorShape: Qt.SizeBDiagCursor
enabled: !QbzShell.systemTitleBar
onPressed: window.startSystemResize(Qt.TopEdge | Qt.RightEdge)
}
MouseArea {
anchors.left: parent.left; anchors.bottom: parent.bottom; width: 12; height: 12
cursorShape: Qt.SizeBDiagCursor
enabled: !QbzShell.systemTitleBar
onPressed: window.startSystemResize(Qt.BottomEdge | Qt.LeftEdge)
}
MouseArea {
anchors.right: parent.right; anchors.bottom: parent.bottom; width: 12; height: 12
cursorShape: Qt.SizeFDiagCursor
enabled: !QbzShell.systemTitleBar
onPressed: window.startSystemResize(Qt.BottomEdge | Qt.RightEdge)
}
// Splash (SplashScreen.slint): the same 720px dark card as the login
// screen while the silent session restore resolves.
Rectangle {
anchors.fill: parent
color: "#0f0f0f"
visible: QbzSession.screen === "splash"
Rectangle {
anchors.centerIn: parent
width: 720
height: splashColumn.height + 104
radius: 16
color: "#1a1a1a"
Column {
id: splashColumn
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: 52
spacing: 0
Image {
anchors.horizontalCenter: parent.horizontalCenter
source: "assets/qbz-logo.png"
width: 140
height: 140
fillMode: Image.PreserveAspectFit
}
Item { width: 1; height: 8 }
Text {
anchors.horizontalCenter: parent.horizontalCenter
text: "QBZ"
color: "#ffffff"
font.pixelSize: 29
font.weight: Font.DemiBold
font.letterSpacing: 8
}
Item { width: 1; height: 2 }
Text {
anchors.horizontalCenter: parent.horizontalCenter
text: "QOBUZ™ PLAYER"
color: "#888888"
font.pixelSize: 15
font.letterSpacing: 4
}
Item { width: 1; height: 32 }
QbzSpinner {
anchors.horizontalCenter: parent.horizontalCenter
size: 32
}
}
}
}
}