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>[]) for (final cl in byChannel[ch.id] ?? const <rust.BridgeClient>[])
Padding( _clientTile(theme, cl, (depthById[ch.id] ?? 0) * indentPerLevel),
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,
),
),
),
], ],
], ],
); );
} }
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 isSelf = client.id == snapshot.ownClientId;
final inCurrentChannel = client.channel == currentVoiceChannelId;
final outputMuted = isSelf ? localOutputMuted : client.outputMuted; final outputMuted = isSelf ? localOutputMuted : client.outputMuted;
final inputMuted = isSelf ? localInputMuted : client.inputMuted; final inputMuted = isSelf ? localInputMuted : client.inputMuted;
final speaking = isSelf final rawSpeaking = isSelf
? (audioStats?.pttActive ?? false) ? (audioStats?.pttActive ?? false)
: client.isSpeaking; : client.isSpeaking;
final speaking = rawSpeaking && !outputMuted && !inputMuted;
final IconData icon; final IconData icon;
final Color color; final Color color;
@@ -2238,18 +2279,25 @@ class _SnapshotView extends StatelessWidget {
color = theme.colorScheme.error; color = theme.colorScheme.error;
tooltip = 'Microphone muted'; tooltip = 'Microphone muted';
} else if (speaking) { } else if (speaking) {
icon = Icons.volume_up; icon = isSelf ? Icons.mic : Icons.volume_up;
color = theme.colorScheme.primary; color = theme.colorScheme.primary;
tooltip = 'Speaking'; tooltip = 'Speaking';
} else { } else if (inCurrentChannel) {
icon = Icons.volume_up_outlined; icon = isSelf ? Icons.mic_none : Icons.volume_up_outlined;
color = theme.colorScheme.onSurfaceVariant; color = theme.colorScheme.onSurfaceVariant;
tooltip = 'Not speaking'; tooltip = 'Not speaking';
} else {
icon = Icons.person_outline;
color = theme.colorScheme.onSurfaceVariant;
tooltip = 'Outside current channel';
} }
return Tooltip( return (
message: tooltip, icon: Tooltip(
child: Icon(icon, size: 18, color: color), message: tooltip,
child: Icon(icon, size: 18, color: color),
),
isSpeaking: speaking,
); );
} }
} }