fix(android): strengthen user voice indicators

This commit is contained in:
Edison Jwa
2026-05-20 14:52:34 +09:00
parent b21fc16ee6
commit bc1bd89424
+72 -24
View File
@@ -2197,34 +2197,75 @@ class _SnapshotView extends StatelessWidget {
),
),
for (final cl in byChannel[ch.id] ?? const <rust.BridgeClient>[])
Padding(
padding: EdgeInsets.only(
left: ((depthById[ch.id] ?? 0) * indentPerLevel) + 64,
),
child: ListTile(
dense: true,
visualDensity: VisualDensity.compact,
leading: _clientVoiceStatusIcon(theme, cl),
title: Text(
cl.name,
style: cl.isServerQuery
? TextStyle(color: theme.colorScheme.onSurfaceVariant)
: null,
),
),
),
_clientTile(theme, cl, (depthById[ch.id] ?? 0) * indentPerLevel),
],
],
);
}
Widget _clientVoiceStatusIcon(ThemeData theme, rust.BridgeClient client) {
Widget _clientTile(
ThemeData theme,
rust.BridgeClient client,
double channelIndent,
) {
final status = _clientVoiceStatusIcon(theme, client);
final nameStyle = client.isServerQuery
? TextStyle(color: theme.colorScheme.onSurfaceVariant)
: status.isSpeaking
? TextStyle(
color: theme.colorScheme.primary,
fontWeight: FontWeight.w600,
)
: null;
final tile = ListTile(
dense: true,
visualDensity: VisualDensity.compact,
leading: status.icon,
title: Text(client.name, style: nameStyle),
);
return Padding(
padding: EdgeInsets.only(left: channelIndent + 64, right: 8),
child: AnimatedContainer(
duration: const Duration(milliseconds: 120),
curve: Curves.easeOut,
decoration: status.isSpeaking
? BoxDecoration(
color: theme.colorScheme.primaryContainer.withValues(
alpha: 0.45,
),
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: theme.colorScheme.primary.withValues(alpha: 0.55),
width: 1.2,
),
boxShadow: [
BoxShadow(
color: theme.colorScheme.primary.withValues(alpha: 0.14),
blurRadius: 8,
spreadRadius: 1,
),
],
)
: null,
child: tile,
),
);
}
({Widget icon, bool isSpeaking}) _clientVoiceStatusIcon(
ThemeData theme,
rust.BridgeClient client,
) {
final isSelf = client.id == snapshot.ownClientId;
final inCurrentChannel = client.channel == currentVoiceChannelId;
final outputMuted = isSelf ? localOutputMuted : client.outputMuted;
final inputMuted = isSelf ? localInputMuted : client.inputMuted;
final speaking = isSelf
final rawSpeaking = isSelf
? (audioStats?.pttActive ?? false)
: client.isSpeaking;
final speaking = rawSpeaking && !outputMuted && !inputMuted;
final IconData icon;
final Color color;
@@ -2238,18 +2279,25 @@ class _SnapshotView extends StatelessWidget {
color = theme.colorScheme.error;
tooltip = 'Microphone muted';
} else if (speaking) {
icon = Icons.volume_up;
icon = isSelf ? Icons.mic : Icons.volume_up;
color = theme.colorScheme.primary;
tooltip = 'Speaking';
} else {
icon = Icons.volume_up_outlined;
} else if (inCurrentChannel) {
icon = isSelf ? Icons.mic_none : Icons.volume_up_outlined;
color = theme.colorScheme.onSurfaceVariant;
tooltip = 'Not speaking';
} else {
icon = Icons.person_outline;
color = theme.colorScheme.onSurfaceVariant;
tooltip = 'Outside current channel';
}
return Tooltip(
message: tooltip,
child: Icon(icon, size: 18, color: color),
return (
icon: Tooltip(
message: tooltip,
child: Icon(icon, size: 18, color: color),
),
isSpeaking: speaking,
);
}
}