- Add responsive breakpoints (compact <600, medium 600-1023, expanded >=1024) - Add ViewportInfo InheritedWidget for layout-aware descendants - Add inline ChatPanel (380dp right column) for expanded desktop layout - Add channel right-click context menu with Chat option for in-place switching - Add per-target draft persistence via restoredDraft/onDraftChanged callbacks - Fix header chat button to switch to current voice channel when panel open - Fix close = dismiss (preserves last target and draft for reopen) - Add unread dot indicator on channel tiles when chat is closed - Fix audio regression: decimate dBFS computation to every 3rd callback (~31 Hz) to avoid buffer underruns on macOS CoreAudio real-time thread - Add tools/build-macos.sh release build script (7-step process) - Add chat panel switching implementation plan and 3-panel design spec Tests: 183 passed, 2 skipped. Flutter analyze clean.
87 lines
2.5 KiB
Dart
87 lines
2.5 KiB
Dart
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import '../design/breakpoints.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);
|
|
|
|
return SizedBox(
|
|
width: ChanoraBreakpoints.chatPanelWidth,
|
|
child: DecoratedBox(
|
|
decoration: BoxDecoration(
|
|
color: Theme.of(context).colorScheme.surface,
|
|
border: Border(
|
|
left: 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: 'Close chat',
|
|
icon: const Icon(Icons.close),
|
|
onPressed: onClose,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|