import 'package:flutter/material.dart'; import '../api/client.dart'; import '../api/models.dart'; import '../widgets/pipeline_card.dart'; import 'pipeline_editor.dart'; import 'pipeline_detail.dart'; class PipelineListScreen extends StatefulWidget { const PipelineListScreen({super.key}); @override State createState() => _PipelineListScreenState(); } class _PipelineListScreenState extends State { late APIClient _api; List _pipelines = []; bool _loading = true; String? _error; @override void initState() { super.initState(); final url = _parseBaseUrl(); _api = APIClient(baseUrl: url); _load(); } static String _parseBaseUrl() { final uri = Uri.base; return '${uri.scheme}://${uri.host}${uri.port != 80 && uri.port != 443 ? ':${uri.port}' : ''}'; } Future _load() async { setState(() { _loading = true; _error = null; }); try { final pipelines = await _api.listPipelines(); setState(() { _pipelines = pipelines; _loading = false; }); } catch (e) { setState(() { _error = e.toString(); _loading = false; }); } } Future _createPipeline() async { final result = await Navigator.push( context, MaterialPageRoute(builder: (_) => const PipelineEditorScreen()), ); if (result != null) { _pipelines.add(result); setState(() {}); } } void _navigateToDetail(Pipeline p) { Navigator.push( context, MaterialPageRoute(builder: (_) => PipelineDetailScreen(pipeline: p)), ); } Future _deletePipeline(Pipeline p) async { final confirmed = await showDialog( context: context, builder: (ctx) => AlertDialog( title: const Text('Delete Pipeline'), content: Text('Are you sure you want to delete "${p.name}"?'), actions: [ TextButton( onPressed: () => Navigator.pop(ctx, false), child: const Text('Cancel'), ), FilledButton( onPressed: () => Navigator.pop(ctx, true), child: const Text('Delete'), ), ], ), ); if (confirmed != true) return; try { await _api.deletePipeline(p.id); setState(() { _pipelines.removeWhere((pl) => pl.id == p.id); }); } catch (e) { if (mounted) { ScaffoldMessenger.of( context, ).showSnackBar(SnackBar(content: Text(e.toString()))); } } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Zaloopipe'), actions: [ IconButton( icon: const Icon(Icons.refresh), onPressed: _load, tooltip: 'Refresh', ), ], ), body: _loading ? const Center(child: CircularProgressIndicator()) : _error != null ? Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ const Icon(Icons.error_outline, size: 48, color: Colors.red), const SizedBox(height: 16), Text(_error!, textAlign: TextAlign.center), const SizedBox(height: 16), FilledButton(onPressed: _load, child: const Text('Retry')), ], ), ) : _pipelines.isEmpty ? Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ const Icon(Icons.api_outlined, size: 64, color: Colors.grey), const SizedBox(height: 16), const Text( 'No pipelines yet', style: TextStyle(fontSize: 18, color: Colors.grey), ), const SizedBox(height: 8), FilledButton.icon( onPressed: _createPipeline, icon: const Icon(Icons.add), label: const Text('Create Pipeline'), ), ], ), ) : RefreshIndicator( onRefresh: _load, child: ListView.builder( itemCount: _pipelines.length + 1, padding: const EdgeInsets.symmetric(vertical: 8), itemBuilder: (ctx, i) { if (i == _pipelines.length) { return Padding( padding: const EdgeInsets.all(16), child: SizedBox( height: 48, width: double.infinity, child: FilledButton.icon( onPressed: _createPipeline, icon: const Icon(Icons.add), label: const Text('Create Pipeline'), ), ), ); } final p = _pipelines[i]; return PipelineCard( pipeline: p, onTap: () => _navigateToDetail(p), onDelete: () => _deletePipeline(p), ); }, ), ), ); } }