125 lines
3.6 KiB
Dart
125 lines
3.6 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
|
|
import '../../core/network/api_exception.dart';
|
|
import '../../core/theme/theme_x.dart';
|
|
import '../../data/repositories/node_repository.dart';
|
|
import 'widgets/connection_form_dialog.dart';
|
|
import 'widgets/connections_list.dart';
|
|
import 'widgets/no_auth_callout.dart';
|
|
import 'widgets/node_identity_form.dart';
|
|
import 'widgets/theme_toggle.dart';
|
|
|
|
class SettingsScreen extends ConsumerWidget {
|
|
const SettingsScreen({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
return ListView(
|
|
padding: const EdgeInsets.all(24),
|
|
children: [
|
|
_Block(
|
|
title: 'Connections',
|
|
trailing: TextButton.icon(
|
|
onPressed: () => showConnectionFormDialog(context),
|
|
icon: const Icon(Icons.add, size: 17),
|
|
label: const Text('Add connection'),
|
|
),
|
|
child: const ConnectionsList(),
|
|
),
|
|
const SizedBox(height: 22),
|
|
_Block(title: 'Node identity', child: const _NodeIdentitySection()),
|
|
const SizedBox(height: 22),
|
|
_Block(
|
|
title: 'Appearance',
|
|
child: const Padding(
|
|
padding: EdgeInsets.all(16),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Text('Theme'),
|
|
ThemeToggle(),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 22),
|
|
const NoAuthCallout(),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
class _NodeIdentitySection extends ConsumerWidget {
|
|
const _NodeIdentitySection();
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
final nodeAsync = ref.watch(currentNodeProvider);
|
|
|
|
return nodeAsync.when(
|
|
loading: () => const Padding(
|
|
padding: EdgeInsets.all(16),
|
|
child: Row(
|
|
children: [
|
|
SizedBox(width: 14, height: 14, child: CircularProgressIndicator(strokeWidth: 2)),
|
|
SizedBox(width: 10),
|
|
Text('Contacting node…'),
|
|
],
|
|
),
|
|
),
|
|
error: (error, stackTrace) {
|
|
final message = error is ApiException ? error.userMessage : error.toString();
|
|
return Padding(
|
|
padding: const EdgeInsets.all(16),
|
|
child: Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Icon(Icons.error_outline, size: 18, color: context.status.critical),
|
|
const SizedBox(width: 10),
|
|
Expanded(
|
|
child: Text(message, style: context.text.bodyMedium?.copyWith(color: context.status.critical)),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
data: (node) {
|
|
if (node == null) {
|
|
return const Padding(
|
|
padding: EdgeInsets.all(16),
|
|
child: Text('No connection selected.'),
|
|
);
|
|
}
|
|
return NodeIdentityForm(node: node);
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
class _Block extends StatelessWidget {
|
|
const _Block({required this.title, required this.child, this.trailing});
|
|
|
|
final String title;
|
|
final Widget child;
|
|
final Widget? trailing;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Text(title, style: context.text.titleMedium),
|
|
trailing ?? const SizedBox.shrink(),
|
|
],
|
|
),
|
|
const SizedBox(height: 10),
|
|
Card(child: child),
|
|
],
|
|
);
|
|
}
|
|
}
|