Files
Flora/qml/dialogs/SettingsDialog.qml
grendervill 417d0273b7 Инкрементальный индекс, пресеты автосейва, диалог Настройки
- VaultIndex: updateFile/removeFile/syncIncremental (mtime+size), полный рескан только на старте/смене/внешних изменениях; relink висячих [[ссылок]] при создании файла; FileStore.externalChanged для внешних правок
- QML: сейвы и правки идут точечно, дерево — через syncIncremental
- Настройки: пресеты safe/balanced/eco/manual (диск 2/5/10с/выкл, коммит после паузы 5/15/60с/вручную), диалог с +/-, шкалами и подсказкой; коммит только в простое, в manual — по Ctrl+S
- Удалены highlightedCode, словный merge, fileDiffText/Html, 2-arg fileHistory; renderInner без побочек
- Тесты: инкремент индекса, пресеты, autosaveEnabled, ~~~-блоки
2026-09-06 23:02:05 +03:00

225 lines
9.7 KiB
QML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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 }
}
}
}
}