Files
Flora/qml/dialogs/SettingsDialog.qml
T

225 lines
9.7 KiB
QML
Raw Normal View History

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Flora
Dialog {
id: root
// Наведённый вариант (для живой подсказки), иначе — выбранный
property string hoveredPreset: ""
function presetById(id) {
for (let i = 0; i < presets.length; ++i)
if (presets[i].id === id) return presets[i]
return presets[1]
}
property var shownPreset: presetById(hoveredPreset.length > 0 ? hoveredPreset : settingsStore.autosavePreset)
property var presets: [
{
id: "safe", name: qsTr("Максимум сохранности"),
desc: qsTr("На диск — каждые 2 с, версия в историю — после 5 с паузы"),
pros: [qsTr("Текст почти невозможно потерять"), qsTr("Подробная история — легко откатить любой момент")],
cons: [qsTr("Больше коммитов при долгой печати"), qsTr("Чаще пишет на диск")],
meters: [["disk", 5], ["commits", 4], ["load", 4]]
},
{
id: "balanced", name: qsTr("Сбалансированный"),
desc: qsTr("На диск — каждые 5 с, версия в историю — после 15 с паузы"),
pros: [qsTr("Разумный баланс потерь и чистоты истории"), qsTr("Версии только после паузы — без мусора")],
cons: [qsTr("До 5 секунд текста живёт только в памяти")],
meters: [["disk", 3], ["commits", 3], ["load", 3]]
},
{
id: "eco", name: qsTr("Экономный"),
desc: qsTr("На диск — каждые 10 с, версия в историю — после минуты паузы"),
pros: [qsTr("Минимум нагрузки — для слабых дисков и огромных хранилищ"), qsTr("История чистая, только вехи")],
cons: [qsTr("До 10 секунд текста живёт только в памяти"), qsTr("Промежуточные мысли в историю не попадут")],
meters: [["disk", 2], ["commits", 2], ["load", 2]]
},
{
id: "manual", name: qsTr("Вручную"),
desc: qsTr("Без таймеров: Ctrl+S сохраняет на диск и делает версию"),
pros: [qsTr("Полный контроль, ноль фоновой работы")],
cons: [qsTr("Забыли Ctrl+S — потеряли"), qsTr("История растёт только от ваших рук")],
meters: [["disk", 1], ["commits", 1], ["load", 1]]
}
]
function meterName(key) {
if (key === "disk") return qsTr("Запись на диск")
if (key === "commits") return qsTr("Коммиты в историю")
return qsTr("Фоновая нагрузка")
}
title: qsTr("Настройки")
modal: true
width: 640
height: 620
anchors.centerIn: parent
closePolicy: Dialog.CloseOnEscape | Dialog.CloseOnPressOutside
standardButtons: Dialog.Close
background: Rectangle { color: Theme.surface; border.color: Theme.borderStrong; radius: 10 }
ColumnLayout {
anchors.fill: parent
spacing: 10
// Подсказка: как читать шкалу
Rectangle {
Layout.fillWidth: true
color: Theme.bgAlt
border.color: Theme.border
radius: 8
Layout.preferredHeight: hintLabel.implicitHeight + 16
Label {
id: hintLabel
anchors.fill: parent
anchors.margins: 8
wrapMode: Text.Wrap
color: Theme.textSecondary
font.pixelSize: 11
text: qsTr("Как выбирать: чем меньше галочек — тем проще и легче решение. " +
"Берите самое простое, которого вам хватает: обычно это «Сбалансированный», " +
"для слабого железа или огромных хранилищ — «Экономный».")
}
}
Label {
text: qsTr("Автосохранение")
font.bold: true
color: Theme.text
font.pixelSize: 13
}
ButtonGroup { id: presetGroup }
Repeater {
model: root.presets
delegate: Rectangle {
required property var modelData
Layout.fillWidth: true
height: 52
radius: 8
color: modelData.id === settingsStore.autosavePreset ? Theme.surfaceSelected
: (rowHover.hovered ? Theme.surfaceHover : Theme.bgAlt)
border.color: modelData.id === settingsStore.autosavePreset ? Theme.accent : Theme.border
border.width: modelData.id === settingsStore.autosavePreset ? 1 : 0
RowLayout {
anchors.fill: parent
anchors.leftMargin: 8
anchors.rightMargin: 8
spacing: 8
RadioButton {
checked: modelData.id === settingsStore.autosavePreset
ButtonGroup.group: presetGroup
onClicked: settingsStore.autosavePreset = modelData.id
}
ColumnLayout {
Layout.fillWidth: true
spacing: 2
Label {
text: modelData.name
font.bold: true
color: Theme.text
font.pixelSize: 12
}
Label {
text: modelData.desc
color: Theme.textMuted
font.pixelSize: 11
elide: Text.ElideRight
Layout.fillWidth: true
}
}
}
HoverHandler {
id: rowHover
onHoveredChanged: {
if (hovered) root.hoveredPreset = modelData.id
else if (root.hoveredPreset === modelData.id) root.hoveredPreset = ""
}
}
TapHandler {
onTapped: settingsStore.autosavePreset = modelData.id
}
}
}
// Детали: плюсы/минусы + шкалы выбранного (или наведённого) варианта
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
color: Theme.bgAlt
border.color: Theme.border
radius: 8
ColumnLayout {
anchors.fill: parent
anchors.margins: 10
spacing: 6
Label {
text: root.shownPreset.name
font.bold: true
color: Theme.text
font.pixelSize: 12
}
Repeater {
model: root.shownPreset.pros
delegate: Label {
required property string modelData
Layout.fillWidth: true
wrapMode: Text.Wrap
color: Theme.successText
font.pixelSize: 11
text: "+ " + modelData
}
}
Repeater {
model: root.shownPreset.cons
delegate: Label {
required property string modelData
Layout.fillWidth: true
wrapMode: Text.Wrap
color: Theme.errorText
font.pixelSize: 11
text: "− " + modelData
}
}
Rectangle { Layout.fillWidth: true; height: 1; color: Theme.divider }
Repeater {
model: root.shownPreset.meters
delegate: RowLayout {
id: meterRow
required property var modelData
property string meterKey: modelData[0]
property int meterLevel: modelData[1]
Layout.fillWidth: true
spacing: 8
Label {
text: root.meterName(meterRow.meterKey)
color: Theme.textSecondary
font.pixelSize: 11
Layout.preferredWidth: 140
}
Row {
spacing: 2
Repeater {
model: 5
Label {
required property int index
text: "✓"
font.pixelSize: 11
font.bold: true
color: index < meterRow.meterLevel ? Theme.accent : Theme.textFaint
}
}
}
}
}
Item { Layout.fillHeight: true }
}
}
}
}