diff --git a/lib/features/auth/views/authentication_page.dart b/lib/features/auth/views/authentication_page.dart index 99455a9..37bc947 100644 --- a/lib/features/auth/views/authentication_page.dart +++ b/lib/features/auth/views/authentication_page.dart @@ -2,7 +2,6 @@ import 'dart:io' show Platform; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_animate/flutter_animate.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; diff --git a/lib/features/auth/views/connection_issue_page.dart b/lib/features/auth/views/connection_issue_page.dart index ca2b2d2..ecbbd3e 100644 --- a/lib/features/auth/views/connection_issue_page.dart +++ b/lib/features/auth/views/connection_issue_page.dart @@ -61,7 +61,7 @@ class _ConnectionIssuePageState extends ConsumerState { Expanded( child: Center( child: ConstrainedBox( - constraints: const BoxConstraints(maxWidth: 420), + constraints: const BoxConstraints(maxWidth: 480), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, @@ -71,13 +71,13 @@ class _ConnectionIssuePageState extends ConsumerState { const SizedBox(height: Spacing.sm), _buildServerDetails(context, activeServer), ], - const SizedBox(height: Spacing.md), + const SizedBox(height: Spacing.lg), Text( l10n.connectionIssueSubtitle, textAlign: TextAlign.center, style: context.conduitTheme.bodyMedium?.copyWith( color: context.conduitTheme.textSecondary, - height: 1.45, + height: 1.4, ), ), ], @@ -111,27 +111,30 @@ class _ConnectionIssuePageState extends ConsumerState { crossAxisAlignment: CrossAxisAlignment.center, children: [ Container( - width: 72, - height: 72, + width: 64, + height: 64, decoration: BoxDecoration( - color: context.conduitTheme.surfaceContainerHighest, + color: context.conduitTheme.error.withValues(alpha: 0.1), shape: BoxShape.circle, - boxShadow: ConduitShadows.high(context), + border: Border.all( + color: context.conduitTheme.error.withValues(alpha: 0.2), + width: BorderWidth.thin, + ), ), child: Icon( Platform.isIOS ? CupertinoIcons.wifi_exclamationmark : Icons.wifi_off_rounded, color: iconColor, - size: 34, + size: 28, ), ), - const SizedBox(height: Spacing.md), + const SizedBox(height: Spacing.lg), Text( l10n.connectionIssueTitle, textAlign: TextAlign.center, style: context.conduitTheme.headingMedium?.copyWith( - fontWeight: FontWeight.w700, + fontWeight: FontWeight.w600, color: context.conduitTheme.textPrimary, ), ), diff --git a/lib/features/auth/views/server_connection_page.dart b/lib/features/auth/views/server_connection_page.dart index abcc4f4..2b8d034 100644 --- a/lib/features/auth/views/server_connection_page.dart +++ b/lib/features/auth/views/server_connection_page.dart @@ -2,7 +2,6 @@ import 'dart:io' show Platform; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_animate/flutter_animate.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:flutter/services.dart'; @@ -470,9 +469,8 @@ class _ServerConnectionPageState extends ConsumerState { return Column( children: [ InkWell( - onTap: () => setState( - () => _showAdvancedSettings = !_showAdvancedSettings, - ), + onTap: () => + setState(() => _showAdvancedSettings = !_showAdvancedSettings), borderRadius: BorderRadius.circular(AppBorderRadius.button), child: Padding( padding: const EdgeInsets.symmetric( @@ -597,7 +595,9 @@ class _ServerConnectionPageState extends ConsumerState { const SizedBox(width: Spacing.sm), ConduitIconButton( icon: Platform.isIOS ? CupertinoIcons.plus : Icons.add, - onPressed: _customHeaders.length >= 10 ? null : _addCustomHeader, + onPressed: _customHeaders.length >= 10 + ? null + : _addCustomHeader, tooltip: _customHeaders.length >= 10 ? AppLocalizations.of(context)!.maximumHeadersReached : AppLocalizations.of(context)!.addHeader, diff --git a/lib/features/chat/widgets/assistant_message_widget.dart b/lib/features/chat/widgets/assistant_message_widget.dart index 6f5eff3..b159d32 100644 --- a/lib/features/chat/widgets/assistant_message_widget.dart +++ b/lib/features/chat/widgets/assistant_message_widget.dart @@ -320,7 +320,7 @@ class _AssistantMessageWidgetState extends ConsumerState } }); }, - borderRadius: BorderRadius.circular(AppBorderRadius.md), + borderRadius: BorderRadius.circular(AppBorderRadius.small), child: Container( width: double.infinity, padding: const EdgeInsets.symmetric( @@ -328,10 +328,10 @@ class _AssistantMessageWidgetState extends ConsumerState vertical: Spacing.xs, ), decoration: BoxDecoration( - color: theme.surfaceContainer.withValues(alpha: 0.5), - borderRadius: BorderRadius.circular(AppBorderRadius.md), + color: theme.surfaceContainer.withValues(alpha: 0.3), + borderRadius: BorderRadius.circular(AppBorderRadius.small), border: Border.all( - color: theme.dividerColor, + color: theme.dividerColor.withValues(alpha: 0.5), width: BorderWidth.thin, ), ), @@ -379,10 +379,10 @@ class _AssistantMessageWidgetState extends ConsumerState margin: const EdgeInsets.only(top: Spacing.sm), padding: const EdgeInsets.all(Spacing.sm), decoration: BoxDecoration( - color: theme.surfaceContainer.withValues(alpha: 0.3), - borderRadius: BorderRadius.circular(AppBorderRadius.md), + color: theme.surfaceContainer.withValues(alpha: 0.2), + borderRadius: BorderRadius.circular(AppBorderRadius.small), border: Border.all( - color: theme.dividerColor, + color: theme.dividerColor.withValues(alpha: 0.5), width: BorderWidth.thin, ), ), @@ -1168,7 +1168,7 @@ class _AssistantMessageWidgetState extends ConsumerState } }); }, - borderRadius: BorderRadius.circular(AppBorderRadius.md), + borderRadius: BorderRadius.circular(AppBorderRadius.small), child: Container( width: double.infinity, padding: const EdgeInsets.symmetric( @@ -1176,10 +1176,10 @@ class _AssistantMessageWidgetState extends ConsumerState vertical: Spacing.xs, ), decoration: BoxDecoration( - color: theme.surfaceContainer.withValues(alpha: 0.5), - borderRadius: BorderRadius.circular(AppBorderRadius.md), + color: theme.surfaceContainer.withValues(alpha: 0.3), + borderRadius: BorderRadius.circular(AppBorderRadius.small), border: Border.all( - color: theme.dividerColor, + color: theme.dividerColor.withValues(alpha: 0.5), width: BorderWidth.thin, ), ), @@ -1223,10 +1223,10 @@ class _AssistantMessageWidgetState extends ConsumerState margin: const EdgeInsets.only(top: Spacing.sm), padding: const EdgeInsets.all(Spacing.sm), decoration: BoxDecoration( - color: theme.surfaceContainer.withValues(alpha: 0.3), - borderRadius: BorderRadius.circular(AppBorderRadius.md), + color: theme.surfaceContainer.withValues(alpha: 0.2), + borderRadius: BorderRadius.circular(AppBorderRadius.small), border: Border.all( - color: theme.dividerColor, + color: theme.dividerColor.withValues(alpha: 0.5), width: BorderWidth.thin, ), ), @@ -1418,7 +1418,7 @@ class _TimelineRow extends StatelessWidget { return InkWell( onTap: onTap, - borderRadius: BorderRadius.circular(AppBorderRadius.sm), + borderRadius: BorderRadius.circular(AppBorderRadius.small), child: wrapped, ); } @@ -1643,15 +1643,19 @@ class _QueryPills extends StatelessWidget { onTap: () => _launchUri( 'https://www.google.com/search?q=${Uri.encodeComponent(query)}', ), - borderRadius: BorderRadius.circular(AppBorderRadius.sm), + borderRadius: BorderRadius.circular(AppBorderRadius.small), child: Container( padding: const EdgeInsets.symmetric( horizontal: Spacing.sm, - vertical: 6, + vertical: Spacing.xs, ), decoration: BoxDecoration( - color: theme.surfaceContainer.withValues(alpha: 0.4), - borderRadius: BorderRadius.circular(AppBorderRadius.sm), + color: theme.surfaceContainer.withValues(alpha: 0.25), + borderRadius: BorderRadius.circular(AppBorderRadius.small), + border: Border.all( + color: theme.dividerColor.withValues(alpha: 0.3), + width: BorderWidth.thin, + ), ), child: Row( mainAxisSize: MainAxisSize.min, @@ -1703,15 +1707,19 @@ class _LinkPills extends StatelessWidget { .map( (item) => InkWell( onTap: item.url != null ? () => _launchUri(item.url!) : null, - borderRadius: BorderRadius.circular(AppBorderRadius.sm), + borderRadius: BorderRadius.circular(AppBorderRadius.small), child: Container( padding: const EdgeInsets.symmetric( horizontal: Spacing.sm, - vertical: 6, + vertical: Spacing.xs, ), decoration: BoxDecoration( - color: theme.surfaceContainer.withValues(alpha: 0.4), - borderRadius: BorderRadius.circular(AppBorderRadius.sm), + color: theme.surfaceContainer.withValues(alpha: 0.25), + borderRadius: BorderRadius.circular(AppBorderRadius.small), + border: Border.all( + color: theme.dividerColor.withValues(alpha: 0.3), + width: BorderWidth.thin, + ), ), child: Row( mainAxisSize: MainAxisSize.min, @@ -2168,15 +2176,15 @@ class FollowUpSuggestionBar extends StatelessWidget { children: [ Icon( Icons.lightbulb_outline, - size: 14, - color: theme.textSecondary.withValues(alpha: 0.8), + size: 12, + color: theme.textSecondary.withValues(alpha: 0.7), ), const SizedBox(width: Spacing.xxs), Text( 'Continue with', style: TextStyle( fontSize: AppTypography.labelSmall, - color: theme.textSecondary.withValues(alpha: 0.8), + color: theme.textSecondary.withValues(alpha: 0.7), fontWeight: FontWeight.w500, ), ), @@ -2184,7 +2192,7 @@ class FollowUpSuggestionBar extends StatelessWidget { ), const SizedBox(height: Spacing.xs), Wrap( - spacing: Spacing.sm, + spacing: Spacing.xs, runSpacing: Spacing.xs, children: [ for (final suggestion in trimmedSuggestions) @@ -2217,7 +2225,7 @@ class _MinimalFollowUpButton extends StatelessWidget { return InkWell( onTap: enabled ? onPressed : null, - borderRadius: BorderRadius.circular(AppBorderRadius.sm), + borderRadius: BorderRadius.circular(AppBorderRadius.small), child: Container( padding: const EdgeInsets.symmetric( horizontal: Spacing.sm, @@ -2225,14 +2233,14 @@ class _MinimalFollowUpButton extends StatelessWidget { ), decoration: BoxDecoration( color: enabled - ? theme.surfaceContainer.withValues(alpha: 0.3) + ? theme.surfaceContainer.withValues(alpha: 0.2) : theme.surfaceContainer.withValues(alpha: 0.1), - borderRadius: BorderRadius.circular(AppBorderRadius.sm), + borderRadius: BorderRadius.circular(AppBorderRadius.small), border: Border.all( color: enabled - ? theme.buttonPrimary.withValues(alpha: 0.2) - : theme.dividerColor.withValues(alpha: 0.3), - width: 1, + ? theme.buttonPrimary.withValues(alpha: 0.15) + : theme.dividerColor.withValues(alpha: 0.2), + width: BorderWidth.thin, ), ), child: Row( @@ -2240,10 +2248,10 @@ class _MinimalFollowUpButton extends StatelessWidget { children: [ Icon( Icons.arrow_forward, - size: 12, + size: 11, color: enabled - ? theme.buttonPrimary.withValues(alpha: 0.8) - : theme.textSecondary.withValues(alpha: 0.5), + ? theme.buttonPrimary.withValues(alpha: 0.7) + : theme.textSecondary.withValues(alpha: 0.4), ), const SizedBox(width: Spacing.xxs), Flexible( @@ -2251,7 +2259,7 @@ class _MinimalFollowUpButton extends StatelessWidget { label, style: TextStyle( color: enabled - ? theme.buttonPrimary + ? theme.buttonPrimary.withValues(alpha: 0.9) : theme.textSecondary.withValues(alpha: 0.5), fontSize: AppTypography.bodySmall, fontWeight: FontWeight.w500, diff --git a/lib/features/chat/widgets/file_attachment_widget.dart b/lib/features/chat/widgets/file_attachment_widget.dart index 526e967..c8d347c 100644 --- a/lib/features/chat/widgets/file_attachment_widget.dart +++ b/lib/features/chat/widgets/file_attachment_widget.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import '../../../shared/theme/theme_extensions.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:flutter_animate/flutter_animate.dart'; import 'dart:io' show Platform; import 'package:conduit/l10n/app_localizations.dart'; import '../services/file_attachment_service.dart'; @@ -75,10 +74,7 @@ class _FileAttachmentCard extends ConsumerWidget { children: [ Row( children: [ - Text( - fileState.fileIcon, - style: const TextStyle(fontSize: 20), - ), + Text(fileState.fileIcon, style: const TextStyle(fontSize: 20)), const Spacer(), _buildStatusIcon(context), ], @@ -225,10 +221,7 @@ class MessageAttachmentPreview extends StatelessWidget { child: Row( mainAxisSize: MainAxisSize.min, children: [ - const Text( - '📎', - style: TextStyle(fontSize: 14), - ), + const Text('📎', style: TextStyle(fontSize: 14)), const SizedBox(width: Spacing.xs), Text( AppLocalizations.of(context)!.attachmentLabel, diff --git a/lib/features/chat/widgets/user_message_bubble.dart b/lib/features/chat/widgets/user_message_bubble.dart index 20343ef..caa0417 100644 --- a/lib/features/chat/widgets/user_message_bubble.dart +++ b/lib/features/chat/widgets/user_message_bubble.dart @@ -5,7 +5,6 @@ import 'enhanced_attachment.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:flutter_animate/flutter_animate.dart'; import 'dart:io' show Platform; import 'package:conduit/l10n/app_localizations.dart'; import 'package:conduit/shared/widgets/chat_action_button.dart'; @@ -149,13 +148,6 @@ class _UserMessageBubbleState extends ConsumerState borderRadius: BorderRadius.circular( AppBorderRadius.messageBubble, ), - boxShadow: [ - BoxShadow( - color: context.conduitTheme.cardShadow.withValues(alpha: 0.1), - blurRadius: 6, - offset: const Offset(0, 2), - ), - ], ), child: ClipRRect( borderRadius: BorderRadius.circular( @@ -196,15 +188,6 @@ class _UserMessageBubbleState extends ConsumerState borderRadius: BorderRadius.circular( AppBorderRadius.messageBubble, ), - boxShadow: [ - BoxShadow( - color: context.conduitTheme.cardShadow.withValues( - alpha: 0.08, - ), - blurRadius: 4, - offset: const Offset(0, 1), - ), - ], ), child: ClipRRect( borderRadius: BorderRadius.circular( @@ -248,15 +231,6 @@ class _UserMessageBubbleState extends ConsumerState return Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(AppBorderRadius.md), - boxShadow: [ - BoxShadow( - color: context.conduitTheme.cardShadow.withValues( - alpha: 0.06, - ), - blurRadius: 3, - offset: const Offset(0, 1), - ), - ], ), child: ClipRRect( borderRadius: BorderRadius.circular(AppBorderRadius.md), @@ -294,13 +268,6 @@ class _UserMessageBubbleState extends ConsumerState borderRadius: BorderRadius.circular( AppBorderRadius.messageBubble, ), - boxShadow: [ - BoxShadow( - color: context.conduitTheme.cardShadow.withValues(alpha: 0.1), - blurRadius: 6, - offset: const Offset(0, 2), - ), - ], ), child: ClipRRect( borderRadius: BorderRadius.circular( @@ -341,15 +308,6 @@ class _UserMessageBubbleState extends ConsumerState borderRadius: BorderRadius.circular( AppBorderRadius.messageBubble, ), - boxShadow: [ - BoxShadow( - color: context.conduitTheme.cardShadow.withValues( - alpha: 0.08, - ), - blurRadius: 4, - offset: const Offset(0, 1), - ), - ], ), child: ClipRRect( borderRadius: BorderRadius.circular( @@ -390,15 +348,6 @@ class _UserMessageBubbleState extends ConsumerState return Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(AppBorderRadius.md), - boxShadow: [ - BoxShadow( - color: context.conduitTheme.cardShadow.withValues( - alpha: 0.06, - ), - blurRadius: 3, - offset: const Offset(0, 1), - ), - ], ), child: ClipRRect( borderRadius: BorderRadius.circular(AppBorderRadius.md), @@ -509,173 +458,148 @@ class _UserMessageBubbleState extends ConsumerState ); return GestureDetector( - onLongPress: () => _toggleActions(), - behavior: HitTestBehavior.translucent, - child: Container( - width: double.infinity, - margin: const EdgeInsets.only( - bottom: Spacing.md, - left: Spacing.xxxl, - right: Spacing.xs, - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - // Display images outside and above the text bubble (iMessage style) - // Prioritize files array over attachmentIds to avoid duplication - if (hasFilesFromArray) ...[ - _buildUserFileImages(), - ] else if (hasImages) ...[ - _buildUserAttachmentImages(), - ], + onLongPress: () => _toggleActions(), + behavior: HitTestBehavior.translucent, + child: Container( + width: double.infinity, + margin: const EdgeInsets.only( + bottom: Spacing.md, + left: Spacing.xxxl, + right: Spacing.xs, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + // Display images outside and above the text bubble (iMessage style) + // Prioritize files array over attachmentIds to avoid duplication + if (hasFilesFromArray) ...[ + _buildUserFileImages(), + ] else if (hasImages) ...[ + _buildUserAttachmentImages(), + ], - // Display text bubble if there's text content - if (hasText) const SizedBox(height: Spacing.xs), - if (hasText) - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Flexible( - child: ConstrainedBox( - constraints: BoxConstraints( - maxWidth: MediaQuery.of(context).size.width * 0.82, + // Display text bubble if there's text content + if (hasText) const SizedBox(height: Spacing.xs), + if (hasText) + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Flexible( + child: ConstrainedBox( + constraints: BoxConstraints( + maxWidth: MediaQuery.of(context).size.width * 0.82, + ), + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: Spacing.chatBubblePadding, + vertical: Spacing.sm, + ), + decoration: BoxDecoration( + color: context.conduitTheme.chatBubbleUser, + borderRadius: BorderRadius.circular( + AppBorderRadius.messageBubble, ), - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: Spacing.chatBubblePadding, - vertical: Spacing.sm, - ), - decoration: BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - context.conduitTheme.chatBubbleUser - .withValues(alpha: 0.95), - context.conduitTheme.chatBubbleUser, - ], - ), - borderRadius: BorderRadius.circular( - AppBorderRadius.messageBubble, - ), - border: Border.all( - color: - context.conduitTheme.chatBubbleUserBorder, - width: BorderWidth.regular, - ), - boxShadow: ConduitShadows.small(context), - ), - child: _isEditing - ? Focus( - focusNode: _editFocusNode, - autofocus: true, - child: DecoratedBox( - decoration: BoxDecoration( - color: inlineEditFill, - borderRadius: BorderRadius.circular( - AppBorderRadius.sm, - ), - border: Border.all( - color: context - .conduitTheme - .inputBorderFocused - .withValues(alpha: 0.6), - width: BorderWidth.thin, - ), - ), - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: Spacing.xs, - vertical: Spacing.xxs, - ), - child: Platform.isIOS - ? CupertinoTextField( - controller: _editController, - maxLines: null, - padding: EdgeInsets.zero, - autofillHints: const [], - style: AppTypography - .chatMessageStyle - .copyWith( - color: - inlineEditTextColor, - ), - decoration: - const BoxDecoration(), - cursorColor: context - .conduitTheme - .buttonPrimary, - onSubmitted: (_) => - _saveInlineEdit(), - ) - : TextField( - controller: _editController, - maxLines: null, - autofillHints: const [], - style: AppTypography - .chatMessageStyle - .copyWith( - color: - inlineEditTextColor, - ), - decoration: - const InputDecoration( - isCollapsed: true, - border: InputBorder.none, - contentPadding: - EdgeInsets.zero, - ), - cursorColor: context - .conduitTheme - .buttonPrimary, - onSubmitted: (_) => - _saveInlineEdit(), - ), - ), - ), - ) - : Text( - widget.message.content, - style: AppTypography.chatMessageStyle - .copyWith( - color: context - .conduitTheme - .chatBubbleUserText, - ), - softWrap: true, - textAlign: TextAlign.left, - textHeightBehavior: - const TextHeightBehavior( - applyHeightToFirstAscent: false, - applyHeightToLastDescent: false, - leadingDistribution: - TextLeadingDistribution.even, - ), - ), + border: Border.all( + color: context.conduitTheme.chatBubbleUserBorder + .withValues(alpha: 0.5), + width: BorderWidth.standard, ), ), + child: _isEditing + ? Focus( + focusNode: _editFocusNode, + autofocus: true, + child: DecoratedBox( + decoration: BoxDecoration( + color: inlineEditFill, + borderRadius: BorderRadius.circular( + AppBorderRadius.small, + ), + border: Border.all( + color: context + .conduitTheme + .inputBorderFocused + .withValues(alpha: 0.5), + width: BorderWidth.thin, + ), + ), + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: Spacing.xs, + vertical: Spacing.xxs, + ), + child: Platform.isIOS + ? CupertinoTextField( + controller: _editController, + maxLines: null, + padding: EdgeInsets.zero, + autofillHints: const [], + style: AppTypography + .chatMessageStyle + .copyWith( + color: inlineEditTextColor, + ), + decoration: const BoxDecoration(), + cursorColor: context + .conduitTheme + .buttonPrimary, + onSubmitted: (_) => + _saveInlineEdit(), + ) + : TextField( + controller: _editController, + maxLines: null, + autofillHints: const [], + style: AppTypography + .chatMessageStyle + .copyWith( + color: inlineEditTextColor, + ), + decoration: const InputDecoration( + isCollapsed: true, + border: InputBorder.none, + contentPadding: EdgeInsets.zero, + ), + cursorColor: context + .conduitTheme + .buttonPrimary, + onSubmitted: (_) => + _saveInlineEdit(), + ), + ), + ), + ) + : Text( + widget.message.content, + style: AppTypography.chatMessageStyle.copyWith( + color: + context.conduitTheme.chatBubbleUserText, + ), + softWrap: true, + textAlign: TextAlign.left, + textHeightBehavior: const TextHeightBehavior( + applyHeightToFirstAscent: false, + applyHeightToLastDescent: false, + leadingDistribution: + TextLeadingDistribution.even, + ), + ), ), - ], + ), ), - if (hasText) const SizedBox(height: Spacing.xs), - - // Action buttons below the message - if (_showActions) ...[ - const SizedBox(height: Spacing.sm), - _buildUserActionButtons(), ], - ], - ), - ), - ) - .animate() - .fadeIn(duration: AnimationDuration.messageAppear) - .slideX( - begin: AnimationValues.messageSlideDistance, - end: 0, - duration: AnimationDuration.messageSlide, - curve: AnimationCurves.messageSlide, - ); + ), + if (hasText) const SizedBox(height: Spacing.xs), + + // Action buttons below the message + if (_showActions) ...[ + const SizedBox(height: Spacing.sm), + _buildUserActionButtons(), + ], + ], + ), + ), + ); } // Assistant-only message renderer removed. diff --git a/lib/features/navigation/widgets/chats_drawer.dart b/lib/features/navigation/widgets/chats_drawer.dart index fc508d4..f628d1e 100644 --- a/lib/features/navigation/widgets/chats_drawer.dart +++ b/lib/features/navigation/widgets/chats_drawer.dart @@ -565,16 +565,19 @@ class _ChatsDrawerState extends ConsumerState { children: [ Text( title, - style: AppTypography.labelStyle.copyWith(color: theme.textSecondary), + style: AppTypography.labelStyle.copyWith( + color: theme.textSecondary, + fontWeight: FontWeight.w600, + ), ), const SizedBox(width: Spacing.xs), Container( padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), decoration: BoxDecoration( - color: theme.surfaceContainer.withValues(alpha: 0.6), + color: theme.surfaceContainer.withValues(alpha: 0.4), borderRadius: BorderRadius.circular(AppBorderRadius.xs), border: Border.all( - color: theme.dividerColor, + color: theme.dividerColor.withValues(alpha: 0.5), width: BorderWidth.thin, ), ), @@ -1029,18 +1032,15 @@ class _ChatsDrawerState extends ConsumerState { color: isHover ? theme.buttonPrimary.withValues(alpha: 0.08) : theme.surfaceContainer.withValues(alpha: 0.03), - borderRadius: BorderRadius.circular(AppBorderRadius.md), + borderRadius: BorderRadius.circular(AppBorderRadius.small), border: Border.all( color: isHover - ? theme.buttonPrimary.withValues(alpha: 0.6) - : theme.dividerColor, - width: BorderWidth.regular, + ? theme.buttonPrimary.withValues(alpha: 0.5) + : theme.dividerColor.withValues(alpha: 0.5), + width: BorderWidth.standard, ), ), - padding: const EdgeInsets.symmetric( - horizontal: Spacing.md, - vertical: Spacing.sm, - ), + padding: const EdgeInsets.all(Spacing.sm), child: Row( children: [ Icon( @@ -1048,14 +1048,15 @@ class _ChatsDrawerState extends ConsumerState { ? CupertinoIcons.folder_badge_minus : Icons.folder_off_outlined, color: theme.iconPrimary, + size: IconSize.small, ), const SizedBox(width: Spacing.sm), Expanded( child: Text( 'Drop here to remove from folder', - style: AppTypography.bodyMediumStyle.copyWith( + style: AppTypography.bodySmallStyle.copyWith( color: theme.textPrimary, - fontWeight: FontWeight.w600, + fontWeight: FontWeight.w500, ), ), ), @@ -1351,55 +1352,46 @@ class _ChatsDrawerState extends ConsumerState { if (user != null) ...[ const SizedBox(height: Spacing.sm), Container( - padding: const EdgeInsets.symmetric( - horizontal: Spacing.sm, - vertical: Spacing.xs, - ), + padding: const EdgeInsets.all(Spacing.sm), decoration: BoxDecoration( - color: theme.surfaceContainer.withValues(alpha: 0.05), - borderRadius: BorderRadius.circular(AppBorderRadius.md), + color: theme.surfaceContainer.withValues(alpha: 0.3), + borderRadius: BorderRadius.circular(AppBorderRadius.small), border: Border.all( - color: theme.dividerColor, - width: BorderWidth.regular, + color: theme.dividerColor.withValues(alpha: 0.5), + width: BorderWidth.standard, ), - boxShadow: ConduitShadows.card(context), ), child: Row( children: [ Container( - width: IconSize.xl, - height: IconSize.xl, + width: 36, + height: 36, decoration: BoxDecoration( borderRadius: BorderRadius.circular( AppBorderRadius.avatar, ), border: Border.all( - color: theme.buttonPrimary.withValues(alpha: 0.35), + color: theme.buttonPrimary.withValues(alpha: 0.25), width: BorderWidth.thin, ), ), clipBehavior: Clip.antiAlias, child: UserAvatar( - size: IconSize.xl, + size: 36, imageUrl: avatarUrl, fallbackText: initial, ), ), - const SizedBox(width: Spacing.xs), + const SizedBox(width: Spacing.sm), Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - displayName, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: AppTypography.bodySmallStyle.copyWith( - color: theme.textPrimary, - fontWeight: FontWeight.w600, - ), - ), - ], + child: Text( + displayName, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: AppTypography.bodySmallStyle.copyWith( + color: theme.textPrimary, + fontWeight: FontWeight.w600, + ), ), ), IconButton( @@ -1408,12 +1400,13 @@ class _ChatsDrawerState extends ConsumerState { Navigator.of(context).maybePop(); context.pushNamed(RouteNames.profile); }, + visualDensity: VisualDensity.compact, icon: Icon( Platform.isIOS ? CupertinoIcons.settings : Icons.settings_rounded, color: theme.iconSecondary, - size: IconSize.listItem, + size: IconSize.small, ), ), ], @@ -1621,19 +1614,14 @@ class _ConversationTile extends StatelessWidget { @override Widget build(BuildContext context) { final theme = context.conduitTheme; - final brightness = Theme.of(context).brightness; final borderRadius = BorderRadius.zero; final Color background = selected - ? theme.buttonPrimary.withValues( - alpha: brightness == Brightness.dark ? 0.28 : 0.16, - ) + ? theme.buttonPrimary.withValues(alpha: 0.1) : theme.surfaceContainer; final Color borderColor = selected - ? theme.buttonPrimary.withValues(alpha: 0.7) + ? theme.buttonPrimary.withValues(alpha: 0.5) : theme.surfaceContainerHighest.withValues(alpha: 0.40); - final List shadow = selected - ? ConduitShadows.low(context) - : const []; + final List shadow = const []; Color? overlayForStates(Set states) { if (states.contains(WidgetState.pressed)) { diff --git a/lib/features/profile/views/app_customization_page.dart b/lib/features/profile/views/app_customization_page.dart index 5ae3bae..38ae3f1 100644 --- a/lib/features/profile/views/app_customization_page.dart +++ b/lib/features/profile/views/app_customization_page.dart @@ -598,7 +598,7 @@ class _PaletteOption extends StatelessWidget { return InkWell( onTap: onSelect, - borderRadius: BorderRadius.circular(AppBorderRadius.md), + borderRadius: BorderRadius.circular(AppBorderRadius.small), child: Padding( padding: const EdgeInsets.symmetric(vertical: Spacing.sm), child: Row( @@ -607,7 +607,7 @@ class _PaletteOption extends StatelessWidget { Icon( isSelected ? Icons.radio_button_checked : Icons.radio_button_off, color: isSelected ? theme.buttonPrimary : theme.iconSecondary, - size: IconSize.md, + size: IconSize.small, ), const SizedBox(width: Spacing.sm), Expanded( @@ -635,7 +635,7 @@ class _PaletteOption extends StatelessWidget { child: Icon( Icons.check_circle, color: theme.buttonPrimary, - size: IconSize.sm, + size: IconSize.small, ), ), ], @@ -674,14 +674,14 @@ class _PaletteColorDot extends StatelessWidget { final theme = context.conduitTheme; return Container( margin: const EdgeInsets.only(right: Spacing.xs), - width: 20, - height: 20, + width: 18, + height: 18, decoration: BoxDecoration( color: color, shape: BoxShape.circle, border: Border.all( - color: theme.dividerColor.withValues(alpha: 0.4), - width: 1.2, + color: theme.dividerColor.withValues(alpha: 0.3), + width: BorderWidth.thin, ), ), ); diff --git a/lib/features/profile/views/profile_page.dart b/lib/features/profile/views/profile_page.dart index 93f9f41..dfaf8db 100644 --- a/lib/features/profile/views/profile_page.dart +++ b/lib/features/profile/views/profile_page.dart @@ -3,7 +3,6 @@ import 'package:flutter/services.dart'; import '../../../shared/theme/theme_extensions.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:flutter_animate/flutter_animate.dart'; import 'package:go_router/go_router.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:url_launcher/url_launcher_string.dart'; @@ -306,11 +305,7 @@ class ProfilePage extends ConsumerWidget { Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ - UserAvatar( - size: 56, - imageUrl: avatarUrl, - fallbackText: initial, - ), + UserAvatar(size: 56, imageUrl: avatarUrl, fallbackText: initial), const SizedBox(width: Spacing.md), Expanded( child: Column( @@ -1187,7 +1182,8 @@ class _DefaultModelBottomSheetState fontWeight: FontWeight.w400, ), ), - ] else if (model.isMultimodal || _modelSupportsReasoning(model)) ...[ + ] else if (model.isMultimodal || + _modelSupportsReasoning(model)) ...[ const SizedBox(height: Spacing.xs), Row( children: [