feat: device detail

This commit is contained in:
Tien Do Nam
2026-08-04 17:42:26 +02:00
parent e4070a2938
commit 51a0f1ec02
7 changed files with 43 additions and 6 deletions
+5 -2
View File
@@ -213,7 +213,9 @@
"verify": "Verify",
"info": {
"name": "Name",
"address": "Address"
"address": "Address",
"version": "Version",
"protocol": "Protocol v{version}"
},
"logs": {
"title": "Logs",
@@ -225,7 +227,8 @@
"verifyPage": {
"title": "Verify",
"icons": "Icons",
"raw": "Raw"
"raw": "Raw",
"question": "Does it look the same on the other device?"
},
"receivePage": {
"subTitle": {
+1 -1
View File
@@ -4,7 +4,7 @@
/// To regenerate, run: `dart run slang`
///
/// Locales: 55
/// Strings: 18572 (337 per locale)
/// Strings: 18575 (337 per locale)
// coverage:ignore-file
// ignore_for_file: type=lint, unused_import
+9
View File
@@ -427,6 +427,9 @@ class Translations$verifyPage$en {
/// en: 'Raw'
String get raw => 'Raw';
/// en: 'Does it look the same on the other device?'
String get question => 'Does it look the same on the other device?';
}
// Path: receivePage
@@ -1322,6 +1325,12 @@ class Translations$deviceDetailsPage$info$en {
/// en: 'Address'
String get address => 'Address';
/// en: 'Version'
String get version => 'Version';
/// en: 'Protocol v{version}'
String protocol({required Object version}) => 'Protocol v${version}';
}
// Path: deviceDetailsPage.logs
+2 -1
View File
@@ -78,7 +78,7 @@ class _DeviceDetailsPageState extends State<DeviceDetailsPage> with Refena {
BigButton(
icon: favoriteEntry != null ? Icons.favorite : Icons.favorite_border,
label: t.deviceDetailsPage.favorite,
filled: false,
filled: favoriteEntry != null,
onTap: () async => await _toggleFavorite(favoriteEntry),
),
const SizedBox(width: 20),
@@ -99,6 +99,7 @@ class _DeviceDetailsPageState extends State<DeviceDetailsPage> with Refena {
children: [
for (final entry in {
t.deviceDetailsPage.info.name: device.alias,
t.deviceDetailsPage.info.version: t.deviceDetailsPage.info.protocol(version: device.version),
if (device.ip != null) t.deviceDetailsPage.info.address: '${device.ip}:${device.port}',
}.entries)
TableRow(
+5
View File
@@ -216,11 +216,13 @@ class SendTab extends StatelessWidget {
child: vm.sendMode == SendMode.multiple
? _MultiSendDeviceListTile(
device: device,
isFavorite: favoriteEntry != null,
nameOverride: favoriteEntry?.alias,
vm: vm,
)
: DeviceListTile(
device: device,
isFavorite: favoriteEntry != null,
nameOverride: favoriteEntry?.alias,
onDetailsTap: () async => await context.push(() => DeviceDetailsPage(device: device)),
onTap: () async => await vm.onTapDevice(context, device),
@@ -513,11 +515,13 @@ class _SendModeButton extends StatelessWidget {
/// An advanced list tile which shows the progress of the file transfer.
class _MultiSendDeviceListTile extends StatelessWidget {
final Device device;
final bool isFavorite;
final String? nameOverride;
final SendTabVm vm;
const _MultiSendDeviceListTile({
required this.device,
required this.isFavorite,
required this.nameOverride,
required this.vm,
});
@@ -548,6 +552,7 @@ class _MultiSendDeviceListTile extends StatelessWidget {
device: device,
info: info,
progress: progress,
isFavorite: isFavorite,
nameOverride: nameOverride,
onDetailsTap: () async => await context.push(() => DeviceDetailsPage(device: device)),
onTap: () async => await vm.onTapDeviceMultiSend(context, device),
+8
View File
@@ -66,6 +66,14 @@ class _VerifyPageState extends State<VerifyPage> {
),
_VerifyMode.raw => SelectableText(combined),
},
const SizedBox(height: 20),
Center(
child: Text(
t.verifyPage.question,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(color: Theme.of(context).colorScheme.onSurfaceVariant),
),
),
],
),
);
+13 -2
View File
@@ -7,6 +7,7 @@ import 'package:localsend_isolates/model/device.dart';
class DeviceListTile extends StatelessWidget {
final Device device;
final bool isFavorite;
/// If not null, this name is used instead of [Device.alias].
/// This is the case when the device is marked as favorite.
@@ -19,6 +20,7 @@ class DeviceListTile extends StatelessWidget {
const DeviceListTile({
required this.device,
this.isFavorite = false,
this.nameOverride,
this.info,
this.progress,
@@ -31,7 +33,16 @@ class DeviceListTile extends StatelessWidget {
final badgeColor = Color.lerp(Theme.of(context).colorScheme.secondaryContainer, Colors.white, 0.3)!;
return CustomListTile(
icon: Icon(device.deviceType.icon, size: 46),
title: Text(nameOverride ?? device.alias, style: const TextStyle(fontSize: 20)),
title: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(nameOverride ?? device.alias, style: const TextStyle(fontSize: 20)),
if (isFavorite) ...[
const SizedBox(width: 5),
Icon(Icons.check_circle, size: 16),
],
],
),
trailing: onDetailsTap != null
? IconButton(
icon: const Icon(Icons.info_outline),
@@ -54,7 +65,7 @@ class DeviceListTile extends StatelessWidget {
DeviceBadge(
backgroundColor: badgeColor,
foregroundColor: Theme.of(context).colorScheme.onSecondaryContainer,
label: 'LAN • HTTP',
label: 'HTTP',
)
else
DeviceBadge(