Files
Forge/lib/src/ui/screens/installed_screen.dart
T

240 lines
9.1 KiB
Dart

import 'package:flutter/cupertino.dart';
import 'package:macos_ui/macos_ui.dart';
import '../../rust/api/packages.dart';
import '../../rust/frb_generated.dart';
class InstalledScreen extends StatefulWidget {
final Function(String name, BackendType backend)? onInspectPackage;
const InstalledScreen({
super.key,
this.onInspectPackage,
});
@override
State<InstalledScreen> createState() => _InstalledScreenState();
}
class _InstalledScreenState extends State<InstalledScreen> {
List<PackageInfo> _packages = [];
String _searchQuery = '';
bool _isLoading = true;
BackendType? _filterBackend;
@override
void initState() {
super.initState();
_loadInstalled();
}
Future<void> _loadInstalled() async {
setState(() => _isLoading = true);
try {
final list =
await RustBridgeApi.getInstalledPackages(backend: _filterBackend);
if (mounted) {
setState(() {
_packages = list;
_isLoading = false;
});
}
} catch (e) {
if (mounted) setState(() => _isLoading = false);
}
}
@override
Widget build(BuildContext context) {
final filtered = _packages.where((p) {
return p.name.toLowerCase().contains(_searchQuery.toLowerCase()) ||
p.description.toLowerCase().contains(_searchQuery.toLowerCase());
}).toList();
return MacosScaffold(
toolBar: ToolBar(
title: const Text('Установленные пакеты'),
leading: MacosTooltip(
message: 'Боковая панель',
child: MacosIconButton(
icon: const MacosIcon(CupertinoIcons.sidebar_left),
onPressed: () => MacosWindowScope.of(context).toggleSidebar(),
),
),
actions: [
// Filter Popup
CustomToolbarItem(
inToolbarBuilder: (context) => Padding(
padding: const EdgeInsets.only(right: 8.0),
child: MacosPopupButton<BackendType?>(
value: _filterBackend,
items: const [
MacosPopupMenuItem(value: null, child: Text('Все бэкенды')),
MacosPopupMenuItem(
value: BackendType.pacman, child: Text('Pacman')),
MacosPopupMenuItem(
value: BackendType.flatpak, child: Text('Flatpak')),
],
onChanged: (b) {
setState(() => _filterBackend = b);
_loadInstalled();
},
),
),
),
CustomToolbarItem(
inToolbarBuilder: (context) => Padding(
padding: const EdgeInsets.only(right: 8.0),
child: SizedBox(
width: 220,
child: MacosTextField(
placeholder: 'Поиск пакета...',
placeholderStyle: const TextStyle(
color: CupertinoColors.systemGrey2,
fontSize: 13,
),
prefix: const Padding(
padding: EdgeInsets.symmetric(horizontal: 6),
child: MacosIcon(
CupertinoIcons.search,
size: 14,
color: CupertinoColors.systemGrey,
),
),
onChanged: (val) => setState(() => _searchQuery = val),
),
),
),
),
],
),
children: [
ContentArea(
builder: (context, scrollController) {
if (_isLoading) {
return const Center(child: ProgressCircle(radius: 16));
}
return ListView.separated(
controller: scrollController,
padding: const EdgeInsets.symmetric(horizontal: 28, vertical: 20),
itemCount: filtered.length,
separatorBuilder: (_, _) => const SizedBox(height: 8),
itemBuilder: (context, idx) {
final pkg = filtered[idx];
final isFlatpak = pkg.backend == BackendType.flatpak;
return Container(
decoration: BoxDecoration(
color: const Color(0xFF222224),
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: CupertinoColors.white.withValues(alpha: 0.08),
width: 0.8,
),
),
child: CupertinoButton(
padding: const EdgeInsets.symmetric(
horizontal: 14, vertical: 12),
alignment: Alignment.centerLeft,
pressedOpacity: 0.7,
onPressed: () {
widget.onInspectPackage?.call(pkg.name, pkg.backend);
},
child: Row(
children: [
MacosIcon(
isFlatpak
? CupertinoIcons.app_badge_fill
: CupertinoIcons.cube_box_fill,
size: 20,
color: isFlatpak
? const Color(0xFF4A90E2)
: const Color(0xFF1793D1),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
pkg.name,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
color: CupertinoColors.white,
),
),
const SizedBox(width: 8),
Text(
pkg.version,
style: const TextStyle(
fontFamily: 'monospace',
color: CupertinoColors.systemGrey,
fontSize: 12,
),
),
const Spacer(),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 6, vertical: 2),
decoration: BoxDecoration(
color: isFlatpak
? const Color(0xFF4A90E2)
.withValues(alpha: 0.12)
: const Color(0xFF1793D1)
.withValues(alpha: 0.12),
borderRadius: BorderRadius.circular(4),
),
child: Text(
pkg.backend.displayName,
style: TextStyle(
fontSize: 10.5,
fontWeight: FontWeight.bold,
color: isFlatpak
? const Color(0xFF4A90E2)
: const Color(0xFF1793D1),
),
),
),
],
),
const SizedBox(height: 3),
Text(
pkg.description,
style: const TextStyle(
fontSize: 12,
color: CupertinoColors.systemGrey,
),
),
],
),
),
const SizedBox(width: 14),
Text(
pkg.formattedSize,
style: const TextStyle(
fontSize: 11.5,
color: CupertinoColors.systemGrey,
),
),
const SizedBox(width: 8),
const MacosIcon(
CupertinoIcons.chevron_right,
size: 13,
color: CupertinoColors.systemGrey,
),
],
),
),
);
},
);
},
),
],
);
}
}