Boot splash and periodic announcement banner
Splash: resources/splash/splash.gif built into the binary, played once by SplashOverlay over a black cover present from the first frame (no UI flash), then fades into the UI; hides icons loading. GIF, so no QtMultimedia/gstreamer. Toggle: splash.enabled. Banner (InfoBanner): metro-style band that fades/slides in with a hold pictogram; text that does not fit runs as a seamless ticker for two rounds. Never takes touches; hidden during splash and settings. Config section banner (enabled, text, intervalSec, showSec, position, accentColor), editable in the web UI and on-device settings; shown once after saving. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import "../components"
|
||||
|
||||
// Announcement banner + boot splash (config sections "banner", "splash").
|
||||
Item {
|
||||
id: page
|
||||
|
||||
signal previewRequested()
|
||||
|
||||
function sync() {
|
||||
accentPicker.hex = settingsContainer.bannerAccentColor
|
||||
if (!textField.activeFocus)
|
||||
textField.text = settingsContainer.bannerText
|
||||
}
|
||||
|
||||
Component.onCompleted: sync()
|
||||
|
||||
Connections {
|
||||
target: settingsContainer
|
||||
function onChanged() { page.sync() }
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "#161628"
|
||||
}
|
||||
|
||||
ScrollView {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
contentWidth: availableWidth
|
||||
contentHeight: col.implicitHeight + 16
|
||||
ScrollBar.vertical.policy: ScrollBar.AsNeeded
|
||||
|
||||
ColumnLayout {
|
||||
id: col
|
||||
width: page.width - 16
|
||||
x: 8
|
||||
y: 8
|
||||
spacing: 12
|
||||
|
||||
BackHeader { title: "Объявление и заставка"; onBack: page.StackView.view.pop() }
|
||||
|
||||
CheckBox {
|
||||
text: "Заставка при запуске"
|
||||
checked: settingsContainer.splashEnabled
|
||||
onToggled: btnController.setSplashEnabled(checked)
|
||||
contentItem: Text {
|
||||
text: parent.text
|
||||
font: parent.font
|
||||
color: "#ffffff"
|
||||
leftPadding: parent.indicator.width + parent.spacing
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
}
|
||||
|
||||
CheckBox {
|
||||
text: "Периодически показывать объявление"
|
||||
checked: settingsContainer.bannerEnabled
|
||||
onToggled: btnController.setBannerValue("enabled", checked)
|
||||
contentItem: Text {
|
||||
text: parent.text
|
||||
font: parent.font
|
||||
color: "#ffffff"
|
||||
leftPadding: parent.indicator.width + parent.spacing
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
text: "Текст объявления"
|
||||
color: "#ffffff"
|
||||
}
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
TextField {
|
||||
id: textField
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 40
|
||||
maximumLength: 200
|
||||
placeholderText: "Для вызова клининга удерживайте кнопку"
|
||||
onAccepted: applyText.clicked()
|
||||
}
|
||||
Button {
|
||||
id: applyText
|
||||
text: "Сохранить"
|
||||
enabled: textField.text.trim() !== settingsContainer.bannerText
|
||||
onClicked: {
|
||||
btnController.setBannerValue("text", textField.text.trim())
|
||||
textField.focus = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LabeledSlider {
|
||||
label: "Раз в, сек"
|
||||
from: 30; to: 1800; stepSize: 30
|
||||
value: settingsContainer.bannerIntervalSec
|
||||
onMoved: btnController.setBannerValue("intervalSec", value)
|
||||
}
|
||||
|
||||
LabeledSlider {
|
||||
label: "Показ, сек"
|
||||
from: 3; to: 30; stepSize: 1
|
||||
value: settingsContainer.bannerShowSec
|
||||
onMoved: btnController.setBannerValue("showSec", value)
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Text {
|
||||
text: "Положение:"
|
||||
color: "#ffffff"
|
||||
}
|
||||
Item { Layout.fillWidth: true }
|
||||
Button {
|
||||
text: "Сверху"
|
||||
highlighted: settingsContainer.bannerPosition === "top"
|
||||
onClicked: btnController.setBannerValue("position", "top")
|
||||
}
|
||||
Button {
|
||||
text: "Снизу"
|
||||
highlighted: settingsContainer.bannerPosition === "bottom"
|
||||
onClicked: btnController.setBannerValue("position", "bottom")
|
||||
}
|
||||
}
|
||||
|
||||
ColorPickerField {
|
||||
id: accentPicker
|
||||
label: "Цвет полосы:"
|
||||
onColorChanged: btnController.setBannerValue("accentColor", hex)
|
||||
}
|
||||
|
||||
SettingsButton {
|
||||
Layout.fillWidth: true
|
||||
text: "Показать сейчас"
|
||||
enabled: settingsContainer.bannerText.length > 0
|
||||
onClicked: page.previewRequested()
|
||||
}
|
||||
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
text: "Объявление не перехватывает нажатия. Если текст не помещается, он прокручивается как бегущая строка."
|
||||
color: "#aaaaaa"
|
||||
font.pixelSize: 12
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
|
||||
Item { Layout.preferredHeight: 8 }
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user