// lib/screens/config_screen.dart import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:cashumit/services/firefly_api_service.dart'; import 'package:cashumit/services/account_cache_service.dart'; import 'package:cashumit/services/account_mirror_service.dart'; class ConfigScreen extends StatefulWidget { const ConfigScreen({super.key}); @override State createState() => _ConfigScreenState(); } class _ConfigScreenState extends State { final _formKey = GlobalKey(); final _urlController = TextEditingController(); final _tokenController = TextEditingController(); bool _isTestingConnection = false; bool _isTestingAuth = false; static const String _prefsKeyUrl = 'firefly_url'; static const String _prefsKeyToken = 'firefly_token'; @override void initState() { super.initState(); _loadConfig(); } /// Memuat konfigurasi yang tersimpan dari shared preferences. Future _loadConfig() async { final prefs = await SharedPreferences.getInstance(); final savedUrl = prefs.getString(_prefsKeyUrl) ?? ''; final savedToken = prefs.getString(_prefsKeyToken) ?? ''; setState(() { _urlController.text = savedUrl; _tokenController.text = savedToken; }); } /// Menyimpan konfigurasi ke shared preferences. Future _saveConfig() async { if (_formKey.currentState!.validate()) { final prefs = await SharedPreferences.getInstance(); await prefs.setString(_prefsKeyUrl, _urlController.text); await prefs.setString(_prefsKeyToken, _tokenController.text); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Konfigurasi tersimpan!')), ); Navigator.pop(context, true); } } } /// Menguji koneksi ke Firefly III. Future _testConnection() async { if (_urlController.text.isEmpty) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Silakan masukkan URL Firefly III terlebih dahulu')), ); } return; } setState(() { _isTestingConnection = true; }); try { final isConnected = await FireflyApiService.testConnection(baseUrl: _urlController.text); if (mounted) { if (isConnected) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Koneksi berhasil!')), ); } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text( 'Koneksi gagal. Periksa URL dan koneksi internet Anda.')), ); } } } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Terjadi kesalahan saat menguji koneksi')), ); } } finally { if (mounted) { setState(() { _isTestingConnection = false; }); } } } /// Menguji autentikasi dengan token. Future _testAuthentication() async { if (_urlController.text.isEmpty || _tokenController.text.isEmpty) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text( 'Silakan masukkan URL dan token Firefly III terlebih dahulu')), ); } return; } setState(() { _isTestingAuth = true; }); try { final isAuthenticated = await FireflyApiService.testAuthentication( baseUrl: _urlController.text, accessToken: _tokenController.text, ); if (mounted) { if (isAuthenticated) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('Autentikasi berhasil!')), ); } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Autentikasi gagal. Periksa token Anda.')), ); } } } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Terjadi kesalahan saat menguji autentikasi')), ); } } finally { if (mounted) { setState(() { _isTestingAuth = false; }); } } } @override void dispose() { _urlController.dispose(); _tokenController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Konfigurasi'), ), body: SingleChildScrollView( padding: const EdgeInsets.all(16.0), child: Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // Firefly III Configuration Section const Text( 'Konfigurasi Firefly III', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), const SizedBox(height: 10), const Text( 'Masukkan detail koneksi ke instance Firefly III Anda:', style: TextStyle(fontSize: 16), ), const SizedBox(height: 20), // TextField untuk URL TextFormField( controller: _urlController, decoration: const InputDecoration( labelText: 'Firefly III URL', hintText: 'https://firefly.yourdomain.com', border: OutlineInputBorder(), ), validator: (value) { if (value == null || value.isEmpty) { return 'URL tidak boleh kosong'; } if (!value.startsWith('http')) { return 'URL harus dimulai dengan http:// atau https://'; } return null; }, ), const SizedBox(height: 20), // TextField untuk Token TextFormField( controller: _tokenController, decoration: const InputDecoration( labelText: 'Personal Access Token', border: OutlineInputBorder(), ), obscureText: true, validator: (value) { if (value == null || value.isEmpty) { return 'Token tidak boleh kosong'; } return null; }, ), const SizedBox(height: 20), // Tombol Simpan ElevatedButton.icon( onPressed: _saveConfig, icon: const Icon(Icons.save), label: const Text('Simpan Konfigurasi'), ), const SizedBox(height: 10), // Tombol Test Connection ElevatedButton.icon( onPressed: _isTestingConnection ? null : _testConnection, icon: _isTestingConnection ? const SizedBox( width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2), ) : const Icon(Icons.link), label: Text(_isTestingConnection ? 'Menguji Koneksi...' : 'Test Koneksi'), ), const SizedBox(height: 10), // Tombol Test Authentication ElevatedButton.icon( onPressed: _isTestingAuth ? null : _testAuthentication, icon: _isTestingAuth ? const SizedBox( width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2), ) : const Icon(Icons.verified_user), label: Text(_isTestingAuth ? 'Menguji Autentikasi...' : 'Test Autentikasi'), ), const SizedBox(height: 30), // Offline Account Configuration Section const Text( 'Pengaturan Akun Offline', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), const SizedBox(height: 10), const Text( 'Atur sinkronisasi data akun ketika server Firefly III terhubung untuk digunakan saat offline.', style: TextStyle(fontSize: 16), ), const SizedBox(height: 20), // Tampilkan informasi waktu sync terakhir FutureBuilder( future: AccountMirrorService.getLastSyncTime(), builder: (context, snapshot) { String syncInfo = 'Waktu sync terakhir: '; if (snapshot.hasData && snapshot.data != null) { final syncTime = snapshot.data!; syncInfo += AccountMirrorService.formatSyncTime(syncTime); } else { syncInfo += 'Belum pernah disinkronisasi'; } return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( syncInfo, style: const TextStyle(fontSize: 14, color: Colors.grey), ), const SizedBox(height: 10), // Tombol untuk sync manual ElevatedButton.icon( onPressed: () async { final prefs = await SharedPreferences.getInstance(); final url = prefs.getString('firefly_url'); final token = prefs.getString('firefly_token'); if (url != null && token != null && url.isNotEmpty && token.isNotEmpty) { try { final revenue = await FireflyApiService.fetchAccounts( baseUrl: url, accessToken: token, type: 'revenue', ); final asset = await FireflyApiService.fetchAccounts( baseUrl: url, accessToken: token, type: 'asset', ); await AccountMirrorService.mirrorAccounts([ ...revenue, ...asset, ]); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Sinkronisasi akun berhasil!')), ); } } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Gagal menyinkronisasi: $e')), ); } } } else { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text( 'Silakan atur URL dan token Firefly III terlebih dahulu')), ); } } }, icon: const Icon(Icons.sync), label: const Text('Sinkronisasi Manual'), style: ElevatedButton.styleFrom( backgroundColor: Colors.blue, ), ), const SizedBox(height: 10), // Tombol untuk menghapus cache akun ElevatedButton.icon( onPressed: () async { await AccountCacheService.clearCache(); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Cache akun dihapus')), ); setState(() {}); } }, icon: const Icon(Icons.delete), label: const Text('Hapus Cache Akun'), style: ElevatedButton.styleFrom( backgroundColor: Colors.orange, ), ), ], ); }, ), ], ), ), ), ); } }