feat: title on the header

This commit is contained in:
cogwheel0
2025-09-19 23:35:46 +05:30
parent c6efb53e3f
commit 1fc1cf9739
3 changed files with 412 additions and 314 deletions

View File

@@ -40,6 +40,7 @@ import '../../../shared/widgets/conduit_components.dart';
import '../../../shared/widgets/middle_ellipsis_text.dart';
import '../../../shared/widgets/modal_safe_area.dart';
import '../../../core/services/settings_service.dart';
import '../../../shared/utils/conversation_context_menu.dart';
// Removed unused PlatformUtils import
import '../../../core/services/platform_service.dart' as ps;
import 'package:flutter/gestures.dart' show DragStartBehavior;
@@ -913,6 +914,7 @@ class _ChatPageState extends ConsumerState<ChatPage> {
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final l10n = AppLocalizations.of(context)!;
// Use select to watch only connectivity status to reduce rebuilds
final isOnline = ref.watch(isOnlineProvider.select((status) => status));
@@ -924,6 +926,28 @@ class _ChatPageState extends ConsumerState<ChatPage> {
// Watch reviewer mode and auto-select model if needed
final isReviewerMode = ref.watch(reviewerModeProvider);
final omitProviderInModelName = ref.watch(
appSettingsProvider.select(
(settings) => settings.omitProviderInModelName,
),
);
final conversationTitle = ref.watch(
activeConversationProvider.select((conv) => conv?.title),
);
final displayConversationTitle = (() {
final trimmed = conversationTitle?.trim();
if (trimmed != null && trimmed.isNotEmpty) {
return trimmed;
}
return l10n.newChat;
})();
final formattedModelName = selectedModel != null
? _formatModelDisplayName(
selectedModel.name,
omitProvider: omitProviderInModelName,
)
: null;
// Keyboard visibility
final keyboardVisible = MediaQuery.of(context).viewInsets.bottom > 0;
// Whether the messages list can actually scroll (avoids showing button when not needed)
@@ -1023,7 +1047,7 @@ class _ChatPageState extends ConsumerState<ChatPage> {
elevation: Elevation.none,
surfaceTintColor: Colors.transparent,
shadowColor: Colors.transparent,
toolbarHeight: kToolbarHeight - 8,
toolbarHeight: kToolbarHeight + 8,
centerTitle: true,
titleSpacing: 0.0,
leading: _isSelectionMode
@@ -1071,13 +1095,35 @@ class _ChatPageState extends ConsumerState<ChatPage> {
(models) => _showModelDropdown(context, ref, models),
);
},
onLongPress: () {
final conversation = ref.read(activeConversationProvider);
if (conversation == null) return;
showConversationContextMenu(
context: context,
ref: ref,
conversation: conversation,
);
},
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
MiddleEllipsisText(
displayConversationTitle,
style: AppTypography.headlineSmallStyle.copyWith(
color: context.conduitTheme.textPrimary,
fontWeight: FontWeight.w600,
fontSize: 18,
height: 1.3,
),
textAlign: TextAlign.center,
semanticsLabel: displayConversationTitle,
),
const SizedBox(height: Spacing.xs),
Transform.translate(
offset: const Offset(0, 0),
child: SizedBox(
height: 28,
height: 24,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
@@ -1114,28 +1160,15 @@ class _ChatPageState extends ConsumerState<ChatPage> {
),
const SizedBox(width: Spacing.xs),
Flexible(
child: Builder(
builder: (context) {
final omitProvider = ref
.watch(appSettingsProvider)
.omitProviderInModelName;
final label = _formatModelDisplayName(
selectedModel.name,
omitProvider: omitProvider,
);
return MiddleEllipsisText(
label,
style: AppTypography.headlineSmallStyle
.copyWith(
color: context
.conduitTheme
.textPrimary,
fontWeight: FontWeight.w600,
),
textAlign: TextAlign.center,
semanticsLabel: label,
);
},
child: MiddleEllipsisText(
formattedModelName!,
style: AppTypography.small.copyWith(
color: context.conduitTheme.textSecondary,
fontWeight: FontWeight.w600,
height: 1.2,
),
textAlign: TextAlign.center,
semanticsLabel: formattedModelName,
),
),
const SizedBox(width: Spacing.xs),
@@ -1169,7 +1202,7 @@ class _ChatPageState extends ConsumerState<ChatPage> {
),
),
),
if (ref.watch(reviewerModeProvider))
if (isReviewerMode)
Padding(
padding: const EdgeInsets.only(top: 2.0),
child: Container(
@@ -1210,13 +1243,35 @@ class _ChatPageState extends ConsumerState<ChatPage> {
(models) => _showModelDropdown(context, ref, models),
);
},
onLongPress: () {
final conversation = ref.read(activeConversationProvider);
if (conversation == null) return;
showConversationContextMenu(
context: context,
ref: ref,
conversation: conversation,
);
},
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
MiddleEllipsisText(
displayConversationTitle,
style: AppTypography.headlineSmallStyle.copyWith(
color: context.conduitTheme.textPrimary,
fontWeight: FontWeight.w600,
fontSize: 18,
height: 1.3,
),
textAlign: TextAlign.center,
semanticsLabel: displayConversationTitle,
),
const SizedBox(height: Spacing.xs),
Transform.translate(
offset: const Offset(0, 0),
child: SizedBox(
height: 28,
height: 24,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
@@ -1253,17 +1308,15 @@ class _ChatPageState extends ConsumerState<ChatPage> {
),
const SizedBox(width: Spacing.xs),
Flexible(
child: Text(
'Choose Model',
style: AppTypography.headlineSmallStyle
.copyWith(
color:
context.conduitTheme.textPrimary,
fontWeight: FontWeight.w600,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
child: MiddleEllipsisText(
l10n.chooseModel,
style: AppTypography.small.copyWith(
color: context.conduitTheme.textSecondary,
fontWeight: FontWeight.w600,
height: 1.2,
),
textAlign: TextAlign.center,
semanticsLabel: l10n.chooseModel,
),
),
const SizedBox(width: Spacing.xs),
@@ -1297,7 +1350,7 @@ class _ChatPageState extends ConsumerState<ChatPage> {
),
),
),
if (ref.watch(reviewerModeProvider))
if (isReviewerMode)
Padding(
padding: const EdgeInsets.only(top: 2.0),
child: Container(