Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions docs/planned-0.4.8.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Milestone 0.4.8: Extension Manager UI

**Theme**: Разработка пользовательского интерфейса менеджера расширений (Marketplace Client). Мы создаем вкладку в настройках или отдельное окно, где пользователь сможет просматривать установленные расширения, искать новые в маркетплейсе, скачивать, обновлять и удалять их. Бэкенд маркетплейса пока будет замокан или использоваться статический JSON для тестов.

| ID | Scope | Summary |
|----|-------|---------|
| **UI-EXT-1** | `ui`, `extensions` | **Extension Manager View** — Создать страницу/диалог для менеджера расширений. Вкладки: Installed, Marketplace, Updates. |
| **UI-EXT-2** | `ui`, `extensions` | **Extension Card Component** — Виджет карточки расширения (иконка, название, автор, версия, описание, кнопка Install/Uninstall). |
| **UI-EXT-3** | `core`, `extensions` | **MarketplaceRepository Mock** — Реализовать моковый репозиторий для симуляции запросов к API маркетплейса (пока бэкенд не готов). |
| **UI-EXT-4** | `core`, `extensions` | **Download & Install Flow** — Интеграция UI с процессом скачивания (прогресс-бар), валидации sha256 и распаковки в `~/.querya/extensions/`. |
| **UI-EXT-5** | `core`, `extensions` | **Uninstall & Update** — Механизмы удаления и обновления локальных расширений через UI менеджера. |

## Заметки
Этот релиз фокусируется на пользовательском опыте (UX/UI) взаимодействия с расширениями. Мы не реализуем сам Marketplace API (он будет в 0.5.0), но закладываем сетевой слой клиента (`MarketplaceRepository`) и мокаем данные для того, чтобы UI можно было использовать и тестировать. Под капотом используются механизмы локального обнаружения, заложенные в релизе 0.4.7.
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import 'package:flutter/material.dart' as material;
import 'package:querya_desktop/core/layout/window_layout.dart';
import 'package:querya_desktop/shared/widgets/widgets.dart';

void showExtensionManagerDialog(material.BuildContext context) {
showAppDialog<void>(
context: context,
builder: (ctx) => material.Dialog(
backgroundColor: material.Colors.transparent,
insetPadding: WindowLayout.dialogSymmetricInsets(ctx),
child: const _ExtensionManagerContent(),
),
);
}

class _ExtensionManagerContent extends material.StatefulWidget {
const _ExtensionManagerContent();

@override
material.State<_ExtensionManagerContent> createState() =>
_ExtensionManagerContentState();
}

class _ExtensionManagerContentState extends material.State<_ExtensionManagerContent> {
int _tabIndex = 0;

@override
material.Widget build(material.BuildContext context) {
final theme = Theme.of(context).colorScheme;
final radius = Theme.of(context).radiusXxl;
final onPopover = theme.popoverForeground;

return material.DefaultTextStyle(
style: material.TextStyle(color: onPopover),
child: material.IconTheme(
data: material.IconThemeData(color: onPopover),
child: material.Container(
constraints: WindowLayout.dialogConstraints(
context,
maxWidth: 800,
minWidth: 600,
maxHeight: 700,
),
decoration: material.BoxDecoration(
color: theme.popover,
borderRadius: material.BorderRadius.circular(radius),
border: material.Border.all(color: theme.border),
),
child: material.ClipRRect(
borderRadius: material.BorderRadius.circular(radius),
child: material.Column(
crossAxisAlignment: material.CrossAxisAlignment.stretch,
children: [
material.Padding(
padding: const material.EdgeInsets.fromLTRB(24, 24, 24, 8),
child: material.Row(
mainAxisAlignment: material.MainAxisAlignment.spaceBetween,
crossAxisAlignment: material.CrossAxisAlignment.center,
children: [
material.Column(
crossAxisAlignment: material.CrossAxisAlignment.start,
children: [
const Text('Extensions').large().semiBold().foreground(),
const material.SizedBox(height: 6),
const Text('Manage local and marketplace extensions')
.muted()
.small(),
],
),
PrimaryButton(
onPressed: () => material.Navigator.of(context).pop(),
child: const Text('Close'),
),
],
),
),
material.Padding(
padding: const material.EdgeInsets.symmetric(
horizontal: 24.0, vertical: 8.0),
child: material.Row(
children: [
_buildTabButton(0, 'Installed'),
const material.SizedBox(width: 8),
_buildTabButton(1, 'Marketplace'),
const material.SizedBox(width: 8),
_buildTabButton(2, 'Updates'),
],
),
),
material.Divider(height: 1, color: theme.border),
material.Expanded(
child: material.IndexedStack(
index: _tabIndex,
children: [
_buildInstalledTab(),
_buildMarketplaceTab(),
_buildUpdatesTab(),
],
),
),
],
),
),
),
),
);
}

material.Widget _buildTabButton(int index, String label) {
final isSelected = _tabIndex == index;
return SecondaryButton(
onPressed: () => setState(() => _tabIndex = index),
child: material.Text(
label,
style: material.TextStyle(
color: isSelected ? Theme.of(context).colorScheme.primary : null,
),
),
);
}

material.Widget _buildInstalledTab() {
return const material.Center(child: Text('Installed extensions will appear here.'));
}

material.Widget _buildMarketplaceTab() {
return const material.Center(child: Text('Marketplace extensions will appear here.'));
}

material.Widget _buildUpdatesTab() {
return const material.Center(child: Text('Extension updates will appear here.'));
}
}
10 changes: 10 additions & 0 deletions lib/features/main_screen/querya_window_title_bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:querya_desktop/core/storage/local_db.dart';
import 'package:querya_desktop/core/theme/querya_theme_scope.dart';
import 'package:querya_desktop/features/connections/driver_manager_dialog.dart';
import 'package:querya_desktop/features/settings/preferences_dialog.dart';
import 'package:querya_desktop/features/extensions/presentation/pages/extension_manager_dialog.dart';
import 'package:querya_desktop/core/actions/sql_editor_actions.dart';
import 'package:shadcn_flutter/shadcn_flutter.dart';

Expand Down Expand Up @@ -134,6 +135,15 @@ class QueryaWindowTitleBar extends StatelessWidget {
onPressed: (ctx) => showPreferencesDialog(ctx),
child: const Text('Preferences…'),
),
const MenuDivider(),
MenuButton(
leading: const material.Icon(
material.Icons.extension_rounded,
size: 18,
),
onPressed: (ctx) => showExtensionManagerDialog(ctx),
child: const Text('Extensions…'),
),
],
child: const Text('Edit'),
),
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: querya_desktop
description: Lightweight desktop SQL/NoSQL client. Flutter (Dart).
version: 0.4.7-a
version: 0.4.8



Expand Down
Loading