@@ -6,6 +6,7 @@ import '../../core/constants/app_constants.dart';
66import '../../core/constants/api_constants.dart' ;
77import '../../core/di/injection_container.dart' ;
88import '../../data/datasources/app_local_datasource.dart' ;
9+ import '../../core/network/dio_client.dart' ;
910
1011/// Server settings page
1112class ServerSettingsPage extends StatefulWidget {
@@ -19,6 +20,9 @@ class _ServerSettingsPageState extends State<ServerSettingsPage> {
1920 final _formKey = GlobalKey <FormState >();
2021 final _hostController = TextEditingController ();
2122 final _portController = TextEditingController ();
23+ final _basicUsernameController = TextEditingController ();
24+ final _basicPasswordController = TextEditingController ();
25+ bool _basicEnabled = false ;
2226
2327 @override
2428 void initState () {
@@ -32,19 +36,30 @@ class _ServerSettingsPageState extends State<ServerSettingsPage> {
3236 final local = sl <AppLocalDataSource >();
3337 final savedHost = await local.getServerHost ();
3438 final savedPort = await local.getServerPort ();
39+ final savedBasicEnabled = await local.getBasicAuthEnabled ();
40+ final savedUsername = await local.getBasicAuthUsername ();
41+ final savedPassword = await local.getBasicAuthPassword ();
3542 if (savedHost != null && savedPort != null && mounted) {
3643 _hostController.text = savedHost;
3744 _portController.text = savedPort.toString ();
3845 // Keep provider state consistent so other parts reflect the same values
3946 appProvider.setServerConfig (savedHost, savedPort);
4047 }
48+ if (mounted) {
49+ _basicEnabled = savedBasicEnabled ?? false ;
50+ _basicUsernameController.text = savedUsername ?? '' ;
51+ _basicPasswordController.text = savedPassword ?? '' ;
52+ setState (() {});
53+ }
4154 });
4255 }
4356
4457 @override
4558 void dispose () {
4659 _hostController.dispose ();
4760 _portController.dispose ();
61+ _basicUsernameController.dispose ();
62+ _basicPasswordController.dispose ();
4863 super .dispose ();
4964 }
5065
@@ -67,13 +82,19 @@ class _ServerSettingsPageState extends State<ServerSettingsPage> {
6782 ),
6883 ],
6984 ),
85+ resizeToAvoidBottomInset: true ,
7086 body: Padding (
7187 padding: const EdgeInsets .all (AppConstants .defaultPadding),
7288 child: Form (
7389 key: _formKey,
74- child: Column (
75- crossAxisAlignment: CrossAxisAlignment .stretch,
76- children: [
90+ child: SingleChildScrollView (
91+ padding: EdgeInsets .only (
92+ bottom: AppConstants .defaultPadding +
93+ MediaQuery .of (context).viewInsets.bottom,
94+ ),
95+ child: Column (
96+ crossAxisAlignment: CrossAxisAlignment .stretch,
97+ children: [
7798 // Connection status card
7899 Consumer <AppProvider >(
79100 builder: (context, appProvider, child) {
@@ -195,6 +216,56 @@ class _ServerSettingsPageState extends State<ServerSettingsPage> {
195216 onPressed: _resetToDefault,
196217 child: const Text ('Reset to Default' ),
197218 ),
219+
220+ const SizedBox (height: AppConstants .defaultPadding),
221+
222+ // Basic authentication section
223+ SwitchListTile (
224+ value: _basicEnabled,
225+ onChanged: (val) {
226+ setState (() {
227+ _basicEnabled = val;
228+ });
229+ },
230+ title: const Text ('Enable Basic Authentication' ),
231+ subtitle: const Text (
232+ 'If enabled, requests will include Basic Authorization header.' ,
233+ ),
234+ ),
235+
236+ if (_basicEnabled) ...[
237+ const SizedBox (height: AppConstants .smallPadding),
238+ TextFormField (
239+ controller: _basicUsernameController,
240+ decoration: const InputDecoration (
241+ labelText: 'Username' ,
242+ prefixIcon: Icon (Icons .person_outline),
243+ ),
244+ validator: (value) {
245+ if (! _basicEnabled) return null ;
246+ if (value == null || value.isEmpty) {
247+ return 'Please enter username' ;
248+ }
249+ return null ;
250+ },
251+ ),
252+ const SizedBox (height: AppConstants .smallPadding),
253+ TextFormField (
254+ controller: _basicPasswordController,
255+ decoration: const InputDecoration (
256+ labelText: 'Password' ,
257+ prefixIcon: Icon (Icons .lock_outline),
258+ ),
259+ obscureText: true ,
260+ validator: (value) {
261+ if (! _basicEnabled) return null ;
262+ if (value == null || value.isEmpty) {
263+ return 'Please enter password' ;
264+ }
265+ return null ;
266+ },
267+ ),
268+ ],
198269 ],
199270 ),
200271 ),
@@ -231,6 +302,7 @@ class _ServerSettingsPageState extends State<ServerSettingsPage> {
231302 ],
232303 ),
233304 ],
305+ ),
234306 ),
235307 ),
236308 ),
@@ -256,12 +328,31 @@ class _ServerSettingsPageState extends State<ServerSettingsPage> {
256328 final success = await appProvider.updateServerConfig (mappedHost, port);
257329
258330 if (success && mounted) {
331+ // Save Basic auth settings
332+ final local = sl <AppLocalDataSource >();
333+ await local.saveBasicAuthEnabled (_basicEnabled);
334+ await local.saveBasicAuthUsername (_basicUsernameController.text.trim ());
335+ await local.saveBasicAuthPassword (_basicPasswordController.text.trim ());
336+
337+ // Apply to Dio client
338+ final dioClient = sl <DioClient >();
339+ if (_basicEnabled &&
340+ _basicUsernameController.text.trim ().isNotEmpty &&
341+ _basicPasswordController.text.trim ().isNotEmpty) {
342+ dioClient.setBasicAuth (
343+ _basicUsernameController.text.trim (),
344+ _basicPasswordController.text.trim (),
345+ );
346+ } else {
347+ dioClient.clearAuth ();
348+ }
349+
259350 final info = 'Settings saved: http://$mappedHost :$port ' ;
260351 ScaffoldMessenger .of (context).showSnackBar (SnackBar (content: Text (info)));
261352 if (mappedHost != host && mounted) {
262353 ScaffoldMessenger .of (context).showSnackBar (
263354 const SnackBar (
264- content: Text ('Android emulator detected: mapped localhost to 10.0.2.2' ),
355+ content: Text ('Android emulator detected: mapped localhost to 10.0.2.2' ),
265356 ),
266357 );
267358 }
0 commit comments