import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick.Dialogs // Мастер первого запуска / добавления хранилища: // 1) выбор папки (новая или с файлами); // 2) автосоздание git-репозитория + подключение провайдеров (опционально); // 3) готово. Dialog { id: root required property bool firstRun readonly property int stepFolder: 0 readonly property int stepSetup: 1 property int step: stepFolder property string vaultPath: "" property string setupStatus: "" signal finished() title: firstRun ? qsTr("Первое знакомство: создайте хранилище") : qsTr("Новое хранилище") modal: true width: 560 height: 480 anchors.centerIn: parent closePolicy: Dialog.NoAutoClose StackLayout { id: stack anchors.fill: parent currentIndex: root.step // ---------- Шаг 1: выбор папки ---------- ColumnLayout { spacing: 12 Label { text: qsTr("Выберите локальную папку — это будет ваше хранилище.\n" + "Можно указать новую папку (будет создана) или уже существующую с файлами.") wrapMode: Text.Wrap Layout.fillWidth: true } RowLayout { Layout.fillWidth: true TextField { id: pathField Layout.fillWidth: true placeholderText: qsTr("Путь к папке…") text: root.vaultPath onTextChanged: root.vaultPath = text } Button { text: qsTr("Обзор…") onClicked: folderDialog.open() } } FolderDialog { id: folderDialog title: qsTr("Выберите папку хранилища") onAccepted: root.vaultPath = selectedFolder.localFile ?? "" } Label { id: step1Error color: "red" wrapMode: Text.Wrap Layout.fillWidth: true text: "" } Item { Layout.fillHeight: true } RowLayout { Layout.fillWidth: true Item { Layout.fillWidth: true } Button { text: qsTr("Отмена") onClicked: root.reject() } Button { text: qsTr("Далее") enabled: root.vaultPath.length > 0 && !busyOverlay.running onClicked: { step1Error.text = "" busyOverlay.running = true const err = vaultManager.createVault(root.vaultPath) busyOverlay.running = false if (err.length > 0) { step1Error.text = err return } root.step = stepSetup } } } } // ---------- Шаг 2: git + провайдеры ---------- ColumnLayout { spacing: 12 Label { text: qsTr("Хранилище готово. Внутри автоматически создан git-репозиторий.\n" + "При желании подключите синхронизацию:") wrapMode: Text.Wrap Layout.fillWidth: true } GridLayout { columns: 2 Layout.fillWidth: true Layout.fillHeight: true columnSpacing: 8 rowSpacing: 8 Button { text: "GitHub"; Layout.fillWidth: true; onClicked: openProviderGuide(0, "GitHub") } Button { text: "GitLab"; Layout.fillWidth: true; onClicked: openProviderGuide(1, "GitLab") } Button { text: "Gitea"; Layout.fillWidth: true; onClicked: openProviderGuide(2, "Gitea") } Button { text: "Nextcloud (WebDAV)"; Layout.fillWidth: true; onClicked: openProviderGuide(3, "Nextcloud (WebDAV)") } Button { text: "Syncthing"; Layout.fillWidth: true; onClicked: openProviderGuide(4, "Syncthing") } function openProviderGuide(idx, name) { providerGuideForButtons.providerIndex = idx providerGuideForButtons.providerName = name providerGuideForButtons.connected = false providerGuideForButtons.open() } Label { color: "#888" Layout.columnSpan: 2 } } RowLayout { Layout.fillWidth: true Item { Layout.fillWidth: true } Button { text: qsTr("Готово") onClicked: { vaultManager.selectVault(root.vaultPath) root.accept() root.finished() } } } } } BusyIndicator { id: busyOverlay anchors.centerIn: parent running: false visible: running } ProviderSetupGuide { id: providerGuideForButtons } onRejected: { if (firstRun) { // Пусть пользователь продолжит позже; хранилище не выбрано. Qt.callLater(() => { console.log("Мастер отменён") }) visible = false } } }