From d435de3bd096b563918ec5b2ba5b45f86f7da388 Mon Sep 17 00:00:00 2001 From: Misaka_Company Date: Wed, 27 May 2026 20:08:35 +0800 Subject: [PATCH] Add settings screen for server URL and API token configuration - New SettingsScreen with server_url and api_token fields, saved to SharedPreferences - Add settings gear icon to HomeScreen AppBar - Allows users to configure backend connection before first upload Co-Authored-By: Claude Opus 4.6 --- lib/screens/home_screen.dart | 13 ++++- lib/screens/settings_screen.dart | 90 ++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 lib/screens/settings_screen.dart diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart index b1f3f4c..53148c6 100644 --- a/lib/screens/home_screen.dart +++ b/lib/screens/home_screen.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import '../widgets/record_bottom_sheet.dart'; +import 'settings_screen.dart'; class HomeScreen extends StatefulWidget { const HomeScreen({super.key}); @@ -64,7 +65,17 @@ class _HomeScreenState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text('SnapLedger')), + appBar: AppBar( + title: const Text('SnapLedger'), + actions: [ + IconButton( + icon: const Icon(Icons.settings), + onPressed: () => Navigator.of(context).push( + MaterialPageRoute(builder: (_) => const SettingsScreen()), + ), + ), + ], + ), body: Center( child: Padding( padding: const EdgeInsets.all(32), diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart new file mode 100644 index 0000000..fd7bdd1 --- /dev/null +++ b/lib/screens/settings_screen.dart @@ -0,0 +1,90 @@ +import 'package:flutter/material.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class SettingsScreen extends StatefulWidget { + const SettingsScreen({super.key}); + + @override + State createState() => _SettingsScreenState(); +} + +class _SettingsScreenState extends State { + final _serverController = TextEditingController(); + final _tokenController = TextEditingController(); + bool _initialized = false; + + @override + void initState() { + super.initState(); + _loadSettings(); + } + + Future _loadSettings() async { + final prefs = await SharedPreferences.getInstance(); + _serverController.text = prefs.getString('server_url') ?? ''; + _tokenController.text = prefs.getString('api_token') ?? ''; + setState(() => _initialized = true); + } + + Future _save() async { + final prefs = await SharedPreferences.getInstance(); + await prefs.setString('server_url', _serverController.text.trim()); + await prefs.setString('api_token', _tokenController.text.trim()); + if (!mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('设置已保存'), duration: Duration(seconds: 1)), + ); + Navigator.of(context).pop(); + } + + @override + void dispose() { + _serverController.dispose(); + _tokenController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('设置')), + body: _initialized + ? Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TextField( + controller: _serverController, + decoration: const InputDecoration( + labelText: '服务器地址', + hintText: 'https://your-server.com', + border: OutlineInputBorder(), + ), + keyboardType: TextInputType.url, + ), + const SizedBox(height: 16), + TextField( + controller: _tokenController, + decoration: const InputDecoration( + labelText: 'API Token', + hintText: '输入认证令牌', + border: OutlineInputBorder(), + ), + ), + const SizedBox(height: 24), + SizedBox( + width: double.infinity, + child: FilledButton.icon( + onPressed: _save, + icon: const Icon(Icons.save), + label: const Text('保存'), + ), + ), + ], + ), + ) + : const Center(child: CircularProgressIndicator()), + ); + } +}