import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:accessible_terminal/state/terminal_provider.dart'; class FileEditorView extends ConsumerStatefulWidget { final String path; const FileEditorView({super.key, required this.path}); @override ConsumerState createState() => _FileEditorViewState(); } class _FileEditorViewState extends ConsumerState { final TextEditingController _controller = TextEditingController(); bool _isLoading = true; bool _isSaving = false; String? _error; @override void initState() { super.initState(); _loadFile(); } Future _loadFile() async { setState(() { _isLoading = true; _error = null; }); try { final sshService = ref.read(sshServiceProvider); final content = await sshService.readFile(widget.path); if (mounted) { setState(() { _controller.text = content; _isLoading = false; }); } } catch (e) { String errorMessage = e.toString(); if (e is FormatException) { errorMessage = 'This file appears to be binary or uses an unsupported encoding. Cannot edit as text.'; } if (mounted) { setState(() { _error = errorMessage; _isLoading = false; }); } } } Future _saveFile() async { setState(() { _isSaving = true; }); try { final sshService = ref.read(sshServiceProvider); await sshService.writeFile(widget.path, _controller.text); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('File saved successfully')), ); Navigator.pop(context); } } catch (e) { if (mounted) { setState(() { _isSaving = false; }); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Error saving file: $e'), backgroundColor: Colors.red), ); } } } @override Widget build(BuildContext context) { final fileName = widget.path.split('/').last; return Scaffold( appBar: AppBar( title: Text('Editing: $fileName'), actions: [ if (!_isLoading && _error == null) IconButton( icon: _isSaving ? const SizedBox(width: 24, height: 24, child: CircularProgressIndicator(strokeWidth: 2, color: Colors.white)) : const Icon(Icons.save), onPressed: _isSaving ? null : _saveFile, tooltip: 'Save File', ), ], ), body: _buildBody(), ); } Widget _buildBody() { if (_isLoading) { return const Center(child: CircularProgressIndicator()); } if (_error != null) { return Center( child: Padding( padding: const EdgeInsets.all(16.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.error, color: Colors.red, size: 48), const SizedBox(height: 16), Text('Error: $_error', textAlign: TextAlign.center), const SizedBox(height: 16), ElevatedButton(onPressed: _loadFile, child: const Text('Retry')), ], ), ), ); } return Padding( padding: const EdgeInsets.all(8.0), child: Semantics( label: 'File content editor', multiline: true, child: TextField( controller: _controller, maxLines: null, expands: true, textAlignVertical: TextAlignVertical.top, autocorrect: false, enableSuggestions: false, style: const TextStyle(fontFamily: 'monospace', fontSize: 16), decoration: const InputDecoration( border: OutlineInputBorder(), hintText: 'Enter file content...', ), ), ), ); } }