Files
BrandManager/lib/views/devices_view.dart
2026-01-25 16:53:41 +01:00

194 lines
4.9 KiB
Dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../models/device.dart';
import '../models/user_info.dart';
import '../services/authentication_manager.dart';
import '../services/brandmeister_client.dart';
import '../widgets/user_header.dart';
import 'device_detail_view.dart';
class DevicesView extends StatefulWidget {
const DevicesView({super.key});
@override
State<DevicesView> createState() => _DevicesViewState();
}
class _DevicesViewState extends State<DevicesView> {
List<Device> _devices = [];
bool _isLoadingDevices = false;
String? _errorMessage;
@override
void initState() {
super.initState();
_loadDevices();
}
Future<void> _loadDevices() async {
setState(() {
_isLoadingDevices = true;
_errorMessage = null;
});
try {
final authManager = context.read<AuthenticationManager>();
final devices = await authManager.getDevices();
setState(() {
_devices = devices;
_isLoadingDevices = false;
});
} on BrandmeisterError catch (e) {
setState(() {
_errorMessage = e.message;
_isLoadingDevices = false;
});
} catch (e) {
setState(() {
_errorMessage = e.toString();
_isLoadingDevices = false;
});
}
}
@override
Widget build(BuildContext context) {
final authManager = context.watch<AuthenticationManager>();
final userInfo = authManager.userInfo;
return Scaffold(
appBar: AppBar(
title: const Text('Devices'),
),
body: RefreshIndicator(
onRefresh: _loadDevices,
child: _buildBody(userInfo),
),
);
}
Widget _buildBody(UserInfo? userInfo) {
if (_isLoadingDevices && _devices.isEmpty) {
return const Center(
child: CircularProgressIndicator(),
);
}
if (_errorMessage != null) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.error_outline,
size: 64,
color: Colors.red[300],
),
const SizedBox(height: 16),
Text(
'Error',
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 8),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 32),
child: Text(
_errorMessage!,
textAlign: TextAlign.center,
style: TextStyle(color: Colors.grey[600]),
),
),
const SizedBox(height: 24),
ElevatedButton.icon(
onPressed: _loadDevices,
icon: const Icon(Icons.refresh),
label: const Text('Retry'),
),
],
),
);
}
if (_devices.isEmpty) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.devices_other,
size: 64,
color: Colors.grey[400],
),
const SizedBox(height: 16),
Text(
'No devices found',
style: Theme.of(context).textTheme.titleLarge,
),
const SizedBox(height: 8),
Text(
'You don\'t have any devices registered',
style: TextStyle(color: Colors.grey[600]),
),
],
),
);
}
return ListView(
children: [
UserHeader(
userInfo: userInfo,
radioId: _devices.isNotEmpty ? _devices.first.id.toString() : null,
),
const Divider(),
..._devices.map((device) => _DeviceRow(
device: device,
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DeviceDetailView(device: device),
),
);
},
)),
],
);
}
}
class _DeviceRow extends StatelessWidget {
final Device device;
final VoidCallback onTap;
const _DeviceRow({
required this.device,
required this.onTap,
});
@override
Widget build(BuildContext context) {
return ListTile(
leading: CircleAvatar(
backgroundColor: Theme.of(context).colorScheme.primaryContainer,
child: Icon(
Icons.settings_input_antenna,
color: Theme.of(context).colorScheme.onPrimaryContainer,
),
),
title: Text(device.callsign ?? 'Unknown'),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('ID: ${device.id}'),
if (device.name != null) Text(device.name!),
Text(device.displayLocation),
],
),
isThreeLine: true,
trailing: const Icon(Icons.chevron_right),
onTap: onTap,
);
}
}