Refine device info layout and add collapsible map legend (#164)

This commit is contained in:
just_stuff_tm
2026-02-12 15:46:28 -05:00
committed by GitHub
parent c52b19b09f
commit fac062a100
2 changed files with 190 additions and 93 deletions
+93 -50
View File
@@ -51,6 +51,7 @@ class _MapScreenState extends State<MapScreen> {
bool _isSelectingPoi = false; bool _isSelectingPoi = false;
bool _hasInitializedMap = false; bool _hasInitializedMap = false;
bool _removedMarkersLoaded = false; bool _removedMarkersLoaded = false;
bool _legendExpanded = false;
@override @override
void initState() { void initState() {
@@ -503,60 +504,102 @@ class _MapScreenState extends State<MapScreen> {
top: 16, top: 16,
right: 16, right: 16,
child: Card( child: Card(
child: Padding( child: Column(
padding: const EdgeInsets.all(12.0), mainAxisSize: MainAxisSize.min,
child: Column( children: [
crossAxisAlignment: CrossAxisAlignment.start, InkWell(
mainAxisSize: MainAxisSize.min, borderRadius: BorderRadius.circular(12),
children: [ onTap: () {
Text( setState(() {
context.l10n.map_nodesCount(nodeCount), _legendExpanded = !_legendExpanded;
style: const TextStyle( });
fontWeight: FontWeight.bold, },
fontSize: 14, child: Padding(
padding: const EdgeInsets.fromLTRB(12, 10, 12, 10),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
context.l10n.map_nodesCount(nodeCount),
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
),
),
Text(
context.l10n.map_pinsCount(markerCount),
style: const TextStyle(
fontWeight: FontWeight.w600,
fontSize: 12,
),
),
],
),
const SizedBox(width: 8),
AnimatedRotation(
turns: _legendExpanded ? 0.5 : 0,
duration: const Duration(milliseconds: 200),
child: const Icon(Icons.expand_more, size: 20),
),
],
), ),
), ),
Text( ),
context.l10n.map_pinsCount(markerCount), AnimatedCrossFade(
style: const TextStyle( firstChild: const SizedBox.shrink(),
fontWeight: FontWeight.bold, secondChild: Padding(
fontSize: 12, padding: const EdgeInsets.fromLTRB(12, 0, 12, 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 6),
_buildLegendItem(
Icons.person,
context.l10n.map_chat,
Colors.blue,
),
_buildLegendItem(
Icons.router,
context.l10n.map_repeater,
Colors.green,
),
_buildLegendItem(
Icons.meeting_room,
context.l10n.map_room,
Colors.purple,
),
_buildLegendItem(
Icons.sensors,
context.l10n.map_sensor,
Colors.orange,
),
_buildLegendItem(
Icons.flag,
context.l10n.map_pinDm,
Colors.blue,
),
_buildLegendItem(
Icons.flag,
context.l10n.map_pinPrivate,
Colors.purple,
),
_buildLegendItem(
Icons.flag,
context.l10n.map_pinPublic,
Colors.orange,
),
],
), ),
), ),
const SizedBox(height: 8), crossFadeState: _legendExpanded
_buildLegendItem( ? CrossFadeState.showSecond
Icons.person, : CrossFadeState.showFirst,
context.l10n.map_chat, duration: const Duration(milliseconds: 200),
Colors.blue, ),
), ],
_buildLegendItem(
Icons.router,
context.l10n.map_repeater,
Colors.green,
),
_buildLegendItem(
Icons.meeting_room,
context.l10n.map_room,
Colors.purple,
),
_buildLegendItem(
Icons.sensors,
context.l10n.map_sensor,
Colors.orange,
),
_buildLegendItem(Icons.flag, context.l10n.map_pinDm, Colors.blue),
_buildLegendItem(
Icons.flag,
context.l10n.map_pinPrivate,
Colors.purple,
),
_buildLegendItem(
Icons.flag,
context.l10n.map_pinPublic,
Colors.orange,
),
],
),
), ),
), ),
); );
+97 -43
View File
@@ -21,6 +21,7 @@ class SettingsScreen extends StatefulWidget {
class _SettingsScreenState extends State<SettingsScreen> { class _SettingsScreenState extends State<SettingsScreen> {
bool _showBatteryVoltage = false; bool _showBatteryVoltage = false;
bool _deviceInfoExpanded = false;
String _appVersion = ''; String _appVersion = '';
@override @override
@@ -74,43 +75,84 @@ class _SettingsScreenState extends State<SettingsScreen> {
MeshCoreConnector connector, MeshCoreConnector connector,
) { ) {
final l10n = context.l10n; final l10n = context.l10n;
return Card( return Card(
child: Padding( child: Column(
padding: const EdgeInsets.all(16), crossAxisAlignment: CrossAxisAlignment.start,
child: Column( children: [
crossAxisAlignment: CrossAxisAlignment.start, InkWell(
children: [ borderRadius: BorderRadius.circular(12),
Text( onTap: () {
l10n.settings_deviceInfo, setState(() {
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), _deviceInfoExpanded = !_deviceInfoExpanded;
), });
const SizedBox(height: 16), },
_buildInfoRow(l10n.settings_infoName, connector.deviceDisplayName), child: Padding(
_buildInfoRow(l10n.settings_infoId, connector.deviceIdLabel), padding: const EdgeInsets.fromLTRB(16, 16, 16, 16),
_buildInfoRow( child: Row(
l10n.settings_infoStatus, children: [
connector.isConnected Expanded(
? l10n.common_connected child: Text(
: l10n.common_disconnected, l10n.settings_deviceInfo,
), style: const TextStyle(
_buildBatteryInfoRow(context, connector), fontSize: 18,
if (connector.selfName != null) fontWeight: FontWeight.bold,
_buildInfoRow(l10n.settings_nodeName, connector.selfName!), ),
if (connector.selfPublicKey != null) ),
_buildInfoRow( ),
l10n.settings_infoPublicKey, AnimatedRotation(
'${pubKeyToHex(connector.selfPublicKey!).substring(0, 16)}...', turns: _deviceInfoExpanded ? 0.5 : 0,
duration: const Duration(milliseconds: 200),
child: const Icon(Icons.expand_more),
),
],
), ),
_buildInfoRow(
l10n.settings_infoContactsCount,
'${connector.contacts.length}',
), ),
_buildInfoRow( ),
l10n.settings_infoChannelCount,
'${connector.channels.length}', AnimatedCrossFade(
firstChild: const SizedBox.shrink(),
secondChild: Padding(
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildInfoRow(
l10n.settings_infoName,
connector.deviceDisplayName,
),
_buildInfoRow(l10n.settings_infoId, connector.deviceIdLabel),
_buildInfoRow(
l10n.settings_infoStatus,
connector.isConnected
? l10n.common_connected
: l10n.common_disconnected,
),
_buildBatteryInfoRow(context, connector),
if (connector.selfName != null)
_buildInfoRow(l10n.settings_nodeName, connector.selfName!),
if (connector.selfPublicKey != null)
_buildInfoRow(
l10n.settings_infoPublicKey,
'${pubKeyToHex(connector.selfPublicKey!).substring(0, 16)}...',
),
_buildInfoRow(
l10n.settings_infoContactsCount,
'${connector.contacts.length}',
),
_buildInfoRow(
l10n.settings_infoChannelCount,
'${connector.channels.length}',
),
],
),
), ),
], crossFadeState: _deviceInfoExpanded
), ? CrossFadeState.showSecond
: CrossFadeState.showFirst,
duration: const Duration(milliseconds: 200),
),
],
), ),
); );
} }
@@ -355,22 +397,33 @@ class _SettingsScreenState extends State<SettingsScreen> {
Color? valueColor, Color? valueColor,
VoidCallback? onTap, VoidCallback? onTap,
}) { }) {
final theme = Theme.of(context);
final row = Padding( final row = Padding(
padding: const EdgeInsets.symmetric(vertical: 4), padding: const EdgeInsets.symmetric(vertical: 10),
child: Row( child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Row( Row(
children: [ children: [
if (leading != null) ...[leading, const SizedBox(width: 8)], if (leading != null) ...[leading, const SizedBox(width: 8)],
Text(label, style: TextStyle(color: Colors.grey[600])), Expanded(
child: Text(
label,
style: theme.textTheme.bodySmall?.copyWith(
color: theme.colorScheme.onSurfaceVariant,
fontWeight: FontWeight.w500,
),
),
),
], ],
), ),
Flexible( const SizedBox(height: 4),
child: Text( Text(
value, value,
style: TextStyle(fontWeight: FontWeight.w500, color: valueColor), style: theme.textTheme.bodyLarge?.copyWith(
overflow: TextOverflow.ellipsis, color: valueColor,
fontWeight: FontWeight.w500,
), ),
), ),
], ],
@@ -379,11 +432,12 @@ class _SettingsScreenState extends State<SettingsScreen> {
if (onTap != null) { if (onTap != null) {
return InkWell( return InkWell(
borderRadius: BorderRadius.circular(6),
onTap: onTap, onTap: onTap,
borderRadius: BorderRadius.circular(4),
child: row, child: row,
); );
} }
return row; return row;
} }