Reduce Linux setup ambiguity and surface desktop input/message failures honestly

Clarify ONNX Runtime guidance with direct-open install hints, restore desktop WebRTC VAD visibility, map mouse side buttons through focused PTT capture/runtime paths, and wait for server acks before showing chat sends as successful.

Constraint: Linux release UX must stay functional when ONNX Runtime is optional and GNOME portal availability varies
Rejected: Keep desktop VAD locked to Silero only | misleads users when ONNX Runtime is skipped
Confidence: medium
Scope-risk: moderate
Directive: Preserve the protocol send-ack wait path for chat so UI success always tracks real server acceptance
Tested: flutter analyze lib/main.dart lib/widgets/chat_views.dart lib/widgets/input_dialogs.dart lib/widgets/startup_dependency_screen.dart; flutter test test/widgets/input_dialogs_test.dart test/widgets/chat_views_test.dart test/services/startup_dependency_check_test.dart test/widgets/startup_dependency_screen_test.dart test/widgets/voice_settings_controls_test.dart test/widgets/audio_processing_config_state_test.dart; cargo test -p chanora_protocol --lib; cargo test -p chanora_audio ptt_backends --lib
Not-tested: Live manual GNOME portal rebind/global PTT on a real desktop session; observer-bot chat against a live server after the sender-name fallback change
This commit is contained in:
Edison Jwa
2026-05-25 11:55:10 +09:00
parent 5c8c6df16b
commit b8df25a195
16 changed files with 1635 additions and 391 deletions
@@ -0,0 +1,133 @@
import 'dart:ffi';
import 'dart:io';
import 'package:flutter_test/flutter_test.dart';
import 'package:chanora_flutter/services/startup_dependency_check.dart';
void main() {
tearDown(() {
debugResetStartupDependencyCheck();
});
test('non-linux hosts skip startup dependency issues', () async {
debugResetStartupDependencyCheck(platformIsLinux: () => false);
final result = await checkStartupDependencies();
expect(result.issues, isEmpty);
});
test('missing SDL2 is reported as required on Debian-like systems', () async {
debugResetStartupDependencyCheck(
platformIsLinux: () => true,
libraryProbe: (candidate) => false,
fileExists: (_) async => false,
osReleaseProvider: () async => 'ID=ubuntu\nID_LIKE=debian\n',
resolvedExecutableProvider: () => '/opt/chanora/chanora_flutter',
currentDirectoryProvider: () => '/tmp',
);
final result = await checkStartupDependencies();
expect(result.hasIssues, isTrue);
final sdl = result.issues.firstWhere(
(issue) => issue.id == 'linux-sdl2-runtime',
);
expect(sdl.isRequired, isTrue);
expect(sdl.installHints.single.command, 'sudo apt install libsdl2-2.0-0');
});
test(
'missing ONNX runtime is reported as recommended when SDL2 is present',
() async {
debugResetStartupDependencyCheck(
platformIsLinux: () => true,
libraryProbe: (candidate) => candidate.contains('SDL2'),
fileExists: (_) async => false,
osReleaseProvider: () async => 'ID=fedora\n',
resolvedExecutableProvider: () => '/opt/chanora/chanora_flutter',
currentDirectoryProvider: () => '/tmp',
currentAbiProvider: () => Abi.linuxX64,
);
final result = await checkStartupDependencies();
expect(result.issues, hasLength(1));
final ort = result.issues.single;
expect(ort.id, 'linux-onnxruntime');
expect(ort.isRequired, isFalse);
expect(
ort.installHints.any(
(hint) =>
hint.command ==
'https://github.com/microsoft/onnxruntime/releases',
),
isTrue,
);
expect(
ort.installHints.any(
(hint) => hint.command == 'onnxruntime-linux-x64-<version>.tgz',
),
isTrue,
);
expect(
ort.installHints.any((hint) => hint.command.contains('ORT_DYLIB_PATH')),
isTrue,
);
expect(
ort.details,
contains(
'This machine needs the Linux x64 CPU archive (onnxruntime-linux-x64-<version>.tgz).',
),
);
},
);
test('bundle-local ONNX runtime clears the recommendation', () async {
debugResetStartupDependencyCheck(
platformIsLinux: () => true,
libraryProbe: (candidate) => candidate.contains('SDL2'),
fileExists: (path) async => path == '/opt/chanora/lib/libonnxruntime.so',
resolvedExecutableProvider: () => '/opt/chanora/chanora_flutter',
currentDirectoryProvider: () => '/tmp',
);
final result = await checkStartupDependencies();
expect(result.issues, isEmpty);
});
test('logging missing startup dependencies appends a log line', () async {
final tempDir = await Directory.systemTemp.createTemp(
'chanora-startup-log',
);
addTearDown(() => tempDir.delete(recursive: true));
final logFile = File('${tempDir.path}/chanora.log');
debugResetStartupDependencyCheck(logFilePathProvider: () => logFile.path);
const result = StartupDependencyCheckResult(
platformLabel: 'Fedora',
issues: [
StartupDependencyIssue(
id: 'linux-sdl2-runtime',
title: 'SDL2 runtime is missing',
summary: 'Audio playback needs SDL2.',
details: ['Install SDL2 and recheck.'],
severity: StartupDependencySeverity.required,
),
],
);
await logStartupDependencyIssues(result);
final text = await logFile.readAsString();
expect(text, contains('[startup_dependency_check]'));
expect(text, contains('platform="Fedora"'));
expect(
text,
contains('issues=[linux-sdl2-runtime:required:SDL2 runtime is missing]'),
);
});
}