- ViewportInfo.updateShouldNotify: compare layoutClass only (not width/height), avoiding unnecessary rebuilds on every resize frame within the same layout class. - ChatPanel: use BorderDirectional(start:) for RTL support. - ChatPanel: localize 'Close chat' tooltip via AppL10n.chatCloseAction. - Inline panel snackbar: localize via AppL10n.chatPanelCollapsedHint. New en/zh ARB entries added. - _saveCurrentDraft(): removed — it was a self-assignment no-op. Draft persistence relies on ChatDetailView's didUpdateWidget (fires onDraftChanged on target switch) and dispose (fires on panel tear-down), both of which already populate _chatDrafts correctly without an explicit save call. - _handleInlineChatViewport layout snackbar: use AppL10n. - Audio level-meter: switch from callback-count (% 3) to time-based gating (std::time::Duration::from_millis(33)), robust to cpal buffer-size or sample-rate changes. Remove level_decimation_counter. - chat_panel_test.dart: add AppL10n.localizationsDelegates so the test resolves l10n keys. Tests: 183 passed, 2 skipped. Dart analyze clean. cargo test -p chanora_audio --lib: 125 passed.
89 lines
2.6 KiB
Dart
89 lines
2.6 KiB
Dart
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import '../design/breakpoints.dart';
|
|
import '../l10n/generated/app_localizations.dart';
|
|
import '../services/snapshot_state_mapper.dart';
|
|
import '../services/ts3_server_link.dart';
|
|
import '../src/rust/api.dart' as rust;
|
|
import 'chat_views.dart';
|
|
|
|
/// Fixed-width inline chat panel for expanded desktop layouts.
|
|
class ChatPanel extends StatelessWidget {
|
|
/// Construct an inline chat panel.
|
|
const ChatPanel({
|
|
super.key,
|
|
required this.messages,
|
|
required this.snapshot,
|
|
required this.target,
|
|
required this.clientName,
|
|
required this.onClose,
|
|
this.restoredDraft,
|
|
this.onDraftChanged,
|
|
this.onTs3ServerLink,
|
|
});
|
|
|
|
/// Backing chat messages shared with the chat route.
|
|
final List<ChatEntry> messages;
|
|
|
|
/// Latest TeamSpeak snapshot.
|
|
final rust.BridgeSnapshot snapshot;
|
|
|
|
/// Chat target shown in the panel.
|
|
final rust.BridgeMessageTarget target;
|
|
|
|
/// Client display name for direct-message and poke targets.
|
|
final String clientName;
|
|
|
|
/// Handle TeamSpeak server links embedded in chat messages.
|
|
final Ts3ServerLinkHandler? onTs3ServerLink;
|
|
|
|
/// Called when the user closes the inline panel.
|
|
final VoidCallback onClose;
|
|
|
|
/// External draft text to restore in the chat detail view.
|
|
final String? restoredDraft;
|
|
|
|
/// Called when the draft text changes.
|
|
final ValueChanged<String>? onDraftChanged;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final currentChannelId = ownClientSnapshotState(snapshot)?.channelId;
|
|
final channelName = snapshotChannelName(snapshot, currentChannelId);
|
|
final l10n = AppL10n.of(context);
|
|
|
|
return SizedBox(
|
|
width: ChanoraBreakpoints.chatPanelWidth,
|
|
child: DecoratedBox(
|
|
decoration: BoxDecoration(
|
|
color: Theme.of(context).colorScheme.surface,
|
|
border: BorderDirectional(
|
|
start: BorderSide(
|
|
color: Theme.of(context).colorScheme.outlineVariant,
|
|
),
|
|
),
|
|
),
|
|
child: ChatDetailView(
|
|
messages: messages,
|
|
snapshot: snapshot,
|
|
target: target,
|
|
clientName: clientName,
|
|
currentChannelId: currentChannelId,
|
|
channelName: channelName,
|
|
onTs3ServerLink: onTs3ServerLink,
|
|
restoredDraft: restoredDraft,
|
|
onDraftChanged: onDraftChanged,
|
|
messageMaxWidth: 500,
|
|
headerTrailing: IconButton(
|
|
tooltip: l10n.chatCloseAction,
|
|
icon: const Icon(Icons.close),
|
|
onPressed: onClose,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|