fix: improve voice and chat controls

This commit is contained in:
Edison Jwa
2026-05-25 18:26:56 +09:00
parent d03ea937e6
commit 487aff4e7c
13 changed files with 351 additions and 147 deletions
@@ -58,6 +58,21 @@ void main() {
);
});
test(
'desktop VAD normalization falls back when ONNX Runtime is unavailable',
() {
expect(
normalizedVadBackend(
rust.BridgeVadBackend.sileroOnnx,
isWindows: false,
isLinux: true,
onnxRuntimeAvailable: false,
),
rust.BridgeVadBackend.webrtcVad,
);
},
);
test('default config matches the current platform fallback', () {
final fallback = defaultAudioProcessingConfig();
final desktop = Platform.isWindows || Platform.isLinux;
@@ -0,0 +1,41 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:chanora_flutter/l10n/generated/app_localizations.dart';
import 'package:chanora_flutter/widgets/connect_widgets.dart';
void main() {
testWidgets('pressing enter in password field submits connection', (
tester,
) async {
var connectCount = 0;
final hostCtl = TextEditingController(text: 'example.com');
final nickCtl = TextEditingController(text: 'alice');
final passwordCtl = TextEditingController();
addTearDown(hostCtl.dispose);
addTearDown(nickCtl.dispose);
addTearDown(passwordCtl.dispose);
await tester.pumpWidget(
MaterialApp(
localizationsDelegates: AppL10n.localizationsDelegates,
supportedLocales: AppL10n.supportedLocales,
home: Scaffold(
body: ConnectForm(
hostCtl: hostCtl,
nickCtl: nickCtl,
passwordCtl: passwordCtl,
onConnect: () => connectCount += 1,
onAddBookmark: () {},
),
),
),
);
await tester.enterText(find.byType(TextField).last, 'secret');
await tester.testTextInput.receiveAction(TextInputAction.done);
await tester.pump();
expect(connectCount, 1);
});
}
@@ -270,7 +270,7 @@ void main() {
},
);
testWidgets('remote client playback options button opens playback sheet', (
testWidgets('remote client row does not show playback ellipsis', (
tester,
) async {
await tester.pumpWidget(
@@ -288,20 +288,12 @@ void main() {
),
);
await tester.pumpAndSettle();
await tester.tap(find.byIcon(Icons.more_horiz));
await tester.pumpAndSettle();
expect(find.text('Per-user playback'), findsOneWidget);
expect(find.text('Mute playback'), findsOneWidget);
expect(find.text('Volume 50%'), findsOneWidget);
expect(
find.byKey(const Key('client-playback-volume-slider')),
findsOneWidget,
);
expect(find.byIcon(Icons.more_horiz), findsNothing);
});
testWidgets('remote client long press opens playback sheet', (tester) async {
testWidgets('remote client long press opens playback menu', (tester) async {
await tester.pumpWidget(
snapshotHarness(
channels: [channel(id: 1, name: 'Default Channel')],
@@ -318,11 +310,11 @@ void main() {
await tester.longPress(find.widgetWithText(ListTile, 'Bob'));
await tester.pumpAndSettle();
expect(find.text('Per-user playback'), findsOneWidget);
expect(find.text('Mute playback'), findsOneWidget);
expect(find.text('Volume 100%'), findsOneWidget);
});
testWidgets('remote client secondary click opens playback sheet', (
testWidgets('remote client secondary click opens playback menu', (
tester,
) async {
await tester.pumpWidget(
@@ -344,11 +336,11 @@ void main() {
);
await tester.pumpAndSettle();
expect(find.text('Per-user playback'), findsOneWidget);
expect(find.text('Mute playback'), findsOneWidget);
expect(find.text('Volume 100%'), findsOneWidget);
});
testWidgets('client playback sheet forwards mute and volume changes', (
testWidgets('client playback menu forwards mute and volume changes', (
tester,
) async {
final changes = <ClientPlaybackPreference>[];
@@ -368,7 +360,7 @@ void main() {
);
await tester.pumpAndSettle();
await tester.tap(find.byIcon(Icons.more_horiz));
await tester.longPress(find.widgetWithText(ListTile, 'Bob'));
await tester.pumpAndSettle();
await tester.tap(find.text('Mute playback'));
@@ -377,13 +369,13 @@ void main() {
expect(changes, isNotEmpty);
expect(changes.last.muted, isTrue);
await tester.drag(
find.byKey(const Key('client-playback-volume-slider')),
const Offset(160, 0),
);
await tester.longPress(find.widgetWithText(ListTile, 'Bob'));
await tester.pumpAndSettle();
await tester.tap(find.text('Volume 200%'), warnIfMissed: false);
await tester.pumpAndSettle();
expect(changes.last.volume, greaterThan(1.0));
expect(changes.last.volume, 2.0);
expect(changes.last.muted, isFalse);
});
testWidgets('spacer channels render as layout rows and keep channel taps', (
@@ -31,6 +31,22 @@ void main() {
]);
});
test('desktop VAD segments disable Silero when ONNX Runtime is missing', () {
final segments = vadBackendSegmentsForAvailability(
desktop: true,
onnxRuntimeAvailable: false,
);
final silero = segments.singleWhere(
(segment) => segment.value == rust.BridgeVadBackend.sileroOnnx,
);
final webrtc = segments.singleWhere(
(segment) => segment.value == rust.BridgeVadBackend.webrtcVad,
);
expect(silero.enabled, isFalse);
expect(webrtc.enabled, isTrue);
});
testWidgets('shared segmented style applies compact visual density', (
tester,
) async {