refactor: improve styling and layout in authentication and connection issue pages

- Removed unused flutter_animate dependency to streamline the codebase.
- Adjusted container dimensions and padding in the connection issue page for better layout consistency.
- Updated spacing values and text styles to enhance readability and align with the overall theme.
- Refined border radius and background colors for improved aesthetics in various components.
- Enhanced the user interface by ensuring consistent styling across authentication and connection issue pages.
This commit is contained in:
cogwheel0
2025-10-05 00:59:32 +05:30
parent f924d894dd
commit c98e4bf959
9 changed files with 247 additions and 336 deletions

View File

@@ -2,7 +2,6 @@ import 'dart:io' show Platform;
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_animate/flutter_animate.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';

View File

@@ -61,7 +61,7 @@ class _ConnectionIssuePageState extends ConsumerState<ConnectionIssuePage> {
Expanded( Expanded(
child: Center( child: Center(
child: ConstrainedBox( child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 420), constraints: const BoxConstraints(maxWidth: 480),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
@@ -71,13 +71,13 @@ class _ConnectionIssuePageState extends ConsumerState<ConnectionIssuePage> {
const SizedBox(height: Spacing.sm), const SizedBox(height: Spacing.sm),
_buildServerDetails(context, activeServer), _buildServerDetails(context, activeServer),
], ],
const SizedBox(height: Spacing.md), const SizedBox(height: Spacing.lg),
Text( Text(
l10n.connectionIssueSubtitle, l10n.connectionIssueSubtitle,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: context.conduitTheme.bodyMedium?.copyWith( style: context.conduitTheme.bodyMedium?.copyWith(
color: context.conduitTheme.textSecondary, color: context.conduitTheme.textSecondary,
height: 1.45, height: 1.4,
), ),
), ),
], ],
@@ -111,27 +111,30 @@ class _ConnectionIssuePageState extends ConsumerState<ConnectionIssuePage> {
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Container( Container(
width: 72, width: 64,
height: 72, height: 64,
decoration: BoxDecoration( decoration: BoxDecoration(
color: context.conduitTheme.surfaceContainerHighest, color: context.conduitTheme.error.withValues(alpha: 0.1),
shape: BoxShape.circle, shape: BoxShape.circle,
boxShadow: ConduitShadows.high(context), border: Border.all(
color: context.conduitTheme.error.withValues(alpha: 0.2),
width: BorderWidth.thin,
),
), ),
child: Icon( child: Icon(
Platform.isIOS Platform.isIOS
? CupertinoIcons.wifi_exclamationmark ? CupertinoIcons.wifi_exclamationmark
: Icons.wifi_off_rounded, : Icons.wifi_off_rounded,
color: iconColor, color: iconColor,
size: 34, size: 28,
), ),
), ),
const SizedBox(height: Spacing.md), const SizedBox(height: Spacing.lg),
Text( Text(
l10n.connectionIssueTitle, l10n.connectionIssueTitle,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: context.conduitTheme.headingMedium?.copyWith( style: context.conduitTheme.headingMedium?.copyWith(
fontWeight: FontWeight.w700, fontWeight: FontWeight.w600,
color: context.conduitTheme.textPrimary, color: context.conduitTheme.textPrimary,
), ),
), ),

View File

@@ -2,7 +2,6 @@ import 'dart:io' show Platform;
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_animate/flutter_animate.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
@@ -470,9 +469,8 @@ class _ServerConnectionPageState extends ConsumerState<ServerConnectionPage> {
return Column( return Column(
children: [ children: [
InkWell( InkWell(
onTap: () => setState( onTap: () =>
() => _showAdvancedSettings = !_showAdvancedSettings, setState(() => _showAdvancedSettings = !_showAdvancedSettings),
),
borderRadius: BorderRadius.circular(AppBorderRadius.button), borderRadius: BorderRadius.circular(AppBorderRadius.button),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
@@ -597,7 +595,9 @@ class _ServerConnectionPageState extends ConsumerState<ServerConnectionPage> {
const SizedBox(width: Spacing.sm), const SizedBox(width: Spacing.sm),
ConduitIconButton( ConduitIconButton(
icon: Platform.isIOS ? CupertinoIcons.plus : Icons.add, icon: Platform.isIOS ? CupertinoIcons.plus : Icons.add,
onPressed: _customHeaders.length >= 10 ? null : _addCustomHeader, onPressed: _customHeaders.length >= 10
? null
: _addCustomHeader,
tooltip: _customHeaders.length >= 10 tooltip: _customHeaders.length >= 10
? AppLocalizations.of(context)!.maximumHeadersReached ? AppLocalizations.of(context)!.maximumHeadersReached
: AppLocalizations.of(context)!.addHeader, : AppLocalizations.of(context)!.addHeader,

View File

@@ -320,7 +320,7 @@ class _AssistantMessageWidgetState extends ConsumerState<AssistantMessageWidget>
} }
}); });
}, },
borderRadius: BorderRadius.circular(AppBorderRadius.md), borderRadius: BorderRadius.circular(AppBorderRadius.small),
child: Container( child: Container(
width: double.infinity, width: double.infinity,
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
@@ -328,10 +328,10 @@ class _AssistantMessageWidgetState extends ConsumerState<AssistantMessageWidget>
vertical: Spacing.xs, vertical: Spacing.xs,
), ),
decoration: BoxDecoration( decoration: BoxDecoration(
color: theme.surfaceContainer.withValues(alpha: 0.5), color: theme.surfaceContainer.withValues(alpha: 0.3),
borderRadius: BorderRadius.circular(AppBorderRadius.md), borderRadius: BorderRadius.circular(AppBorderRadius.small),
border: Border.all( border: Border.all(
color: theme.dividerColor, color: theme.dividerColor.withValues(alpha: 0.5),
width: BorderWidth.thin, width: BorderWidth.thin,
), ),
), ),
@@ -379,10 +379,10 @@ class _AssistantMessageWidgetState extends ConsumerState<AssistantMessageWidget>
margin: const EdgeInsets.only(top: Spacing.sm), margin: const EdgeInsets.only(top: Spacing.sm),
padding: const EdgeInsets.all(Spacing.sm), padding: const EdgeInsets.all(Spacing.sm),
decoration: BoxDecoration( decoration: BoxDecoration(
color: theme.surfaceContainer.withValues(alpha: 0.3), color: theme.surfaceContainer.withValues(alpha: 0.2),
borderRadius: BorderRadius.circular(AppBorderRadius.md), borderRadius: BorderRadius.circular(AppBorderRadius.small),
border: Border.all( border: Border.all(
color: theme.dividerColor, color: theme.dividerColor.withValues(alpha: 0.5),
width: BorderWidth.thin, width: BorderWidth.thin,
), ),
), ),
@@ -1168,7 +1168,7 @@ class _AssistantMessageWidgetState extends ConsumerState<AssistantMessageWidget>
} }
}); });
}, },
borderRadius: BorderRadius.circular(AppBorderRadius.md), borderRadius: BorderRadius.circular(AppBorderRadius.small),
child: Container( child: Container(
width: double.infinity, width: double.infinity,
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
@@ -1176,10 +1176,10 @@ class _AssistantMessageWidgetState extends ConsumerState<AssistantMessageWidget>
vertical: Spacing.xs, vertical: Spacing.xs,
), ),
decoration: BoxDecoration( decoration: BoxDecoration(
color: theme.surfaceContainer.withValues(alpha: 0.5), color: theme.surfaceContainer.withValues(alpha: 0.3),
borderRadius: BorderRadius.circular(AppBorderRadius.md), borderRadius: BorderRadius.circular(AppBorderRadius.small),
border: Border.all( border: Border.all(
color: theme.dividerColor, color: theme.dividerColor.withValues(alpha: 0.5),
width: BorderWidth.thin, width: BorderWidth.thin,
), ),
), ),
@@ -1223,10 +1223,10 @@ class _AssistantMessageWidgetState extends ConsumerState<AssistantMessageWidget>
margin: const EdgeInsets.only(top: Spacing.sm), margin: const EdgeInsets.only(top: Spacing.sm),
padding: const EdgeInsets.all(Spacing.sm), padding: const EdgeInsets.all(Spacing.sm),
decoration: BoxDecoration( decoration: BoxDecoration(
color: theme.surfaceContainer.withValues(alpha: 0.3), color: theme.surfaceContainer.withValues(alpha: 0.2),
borderRadius: BorderRadius.circular(AppBorderRadius.md), borderRadius: BorderRadius.circular(AppBorderRadius.small),
border: Border.all( border: Border.all(
color: theme.dividerColor, color: theme.dividerColor.withValues(alpha: 0.5),
width: BorderWidth.thin, width: BorderWidth.thin,
), ),
), ),
@@ -1418,7 +1418,7 @@ class _TimelineRow extends StatelessWidget {
return InkWell( return InkWell(
onTap: onTap, onTap: onTap,
borderRadius: BorderRadius.circular(AppBorderRadius.sm), borderRadius: BorderRadius.circular(AppBorderRadius.small),
child: wrapped, child: wrapped,
); );
} }
@@ -1643,15 +1643,19 @@ class _QueryPills extends StatelessWidget {
onTap: () => _launchUri( onTap: () => _launchUri(
'https://www.google.com/search?q=${Uri.encodeComponent(query)}', 'https://www.google.com/search?q=${Uri.encodeComponent(query)}',
), ),
borderRadius: BorderRadius.circular(AppBorderRadius.sm), borderRadius: BorderRadius.circular(AppBorderRadius.small),
child: Container( child: Container(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: Spacing.sm, horizontal: Spacing.sm,
vertical: 6, vertical: Spacing.xs,
), ),
decoration: BoxDecoration( decoration: BoxDecoration(
color: theme.surfaceContainer.withValues(alpha: 0.4), color: theme.surfaceContainer.withValues(alpha: 0.25),
borderRadius: BorderRadius.circular(AppBorderRadius.sm), borderRadius: BorderRadius.circular(AppBorderRadius.small),
border: Border.all(
color: theme.dividerColor.withValues(alpha: 0.3),
width: BorderWidth.thin,
),
), ),
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@@ -1703,15 +1707,19 @@ class _LinkPills extends StatelessWidget {
.map( .map(
(item) => InkWell( (item) => InkWell(
onTap: item.url != null ? () => _launchUri(item.url!) : null, onTap: item.url != null ? () => _launchUri(item.url!) : null,
borderRadius: BorderRadius.circular(AppBorderRadius.sm), borderRadius: BorderRadius.circular(AppBorderRadius.small),
child: Container( child: Container(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: Spacing.sm, horizontal: Spacing.sm,
vertical: 6, vertical: Spacing.xs,
), ),
decoration: BoxDecoration( decoration: BoxDecoration(
color: theme.surfaceContainer.withValues(alpha: 0.4), color: theme.surfaceContainer.withValues(alpha: 0.25),
borderRadius: BorderRadius.circular(AppBorderRadius.sm), borderRadius: BorderRadius.circular(AppBorderRadius.small),
border: Border.all(
color: theme.dividerColor.withValues(alpha: 0.3),
width: BorderWidth.thin,
),
), ),
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@@ -2168,15 +2176,15 @@ class FollowUpSuggestionBar extends StatelessWidget {
children: [ children: [
Icon( Icon(
Icons.lightbulb_outline, Icons.lightbulb_outline,
size: 14, size: 12,
color: theme.textSecondary.withValues(alpha: 0.8), color: theme.textSecondary.withValues(alpha: 0.7),
), ),
const SizedBox(width: Spacing.xxs), const SizedBox(width: Spacing.xxs),
Text( Text(
'Continue with', 'Continue with',
style: TextStyle( style: TextStyle(
fontSize: AppTypography.labelSmall, fontSize: AppTypography.labelSmall,
color: theme.textSecondary.withValues(alpha: 0.8), color: theme.textSecondary.withValues(alpha: 0.7),
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
), ),
), ),
@@ -2184,7 +2192,7 @@ class FollowUpSuggestionBar extends StatelessWidget {
), ),
const SizedBox(height: Spacing.xs), const SizedBox(height: Spacing.xs),
Wrap( Wrap(
spacing: Spacing.sm, spacing: Spacing.xs,
runSpacing: Spacing.xs, runSpacing: Spacing.xs,
children: [ children: [
for (final suggestion in trimmedSuggestions) for (final suggestion in trimmedSuggestions)
@@ -2217,7 +2225,7 @@ class _MinimalFollowUpButton extends StatelessWidget {
return InkWell( return InkWell(
onTap: enabled ? onPressed : null, onTap: enabled ? onPressed : null,
borderRadius: BorderRadius.circular(AppBorderRadius.sm), borderRadius: BorderRadius.circular(AppBorderRadius.small),
child: Container( child: Container(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: Spacing.sm, horizontal: Spacing.sm,
@@ -2225,14 +2233,14 @@ class _MinimalFollowUpButton extends StatelessWidget {
), ),
decoration: BoxDecoration( decoration: BoxDecoration(
color: enabled color: enabled
? theme.surfaceContainer.withValues(alpha: 0.3) ? theme.surfaceContainer.withValues(alpha: 0.2)
: theme.surfaceContainer.withValues(alpha: 0.1), : theme.surfaceContainer.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(AppBorderRadius.sm), borderRadius: BorderRadius.circular(AppBorderRadius.small),
border: Border.all( border: Border.all(
color: enabled color: enabled
? theme.buttonPrimary.withValues(alpha: 0.2) ? theme.buttonPrimary.withValues(alpha: 0.15)
: theme.dividerColor.withValues(alpha: 0.3), : theme.dividerColor.withValues(alpha: 0.2),
width: 1, width: BorderWidth.thin,
), ),
), ),
child: Row( child: Row(
@@ -2240,10 +2248,10 @@ class _MinimalFollowUpButton extends StatelessWidget {
children: [ children: [
Icon( Icon(
Icons.arrow_forward, Icons.arrow_forward,
size: 12, size: 11,
color: enabled color: enabled
? theme.buttonPrimary.withValues(alpha: 0.8) ? theme.buttonPrimary.withValues(alpha: 0.7)
: theme.textSecondary.withValues(alpha: 0.5), : theme.textSecondary.withValues(alpha: 0.4),
), ),
const SizedBox(width: Spacing.xxs), const SizedBox(width: Spacing.xxs),
Flexible( Flexible(
@@ -2251,7 +2259,7 @@ class _MinimalFollowUpButton extends StatelessWidget {
label, label,
style: TextStyle( style: TextStyle(
color: enabled color: enabled
? theme.buttonPrimary ? theme.buttonPrimary.withValues(alpha: 0.9)
: theme.textSecondary.withValues(alpha: 0.5), : theme.textSecondary.withValues(alpha: 0.5),
fontSize: AppTypography.bodySmall, fontSize: AppTypography.bodySmall,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,

View File

@@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import '../../../shared/theme/theme_extensions.dart'; import '../../../shared/theme/theme_extensions.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_animate/flutter_animate.dart';
import 'dart:io' show Platform; import 'dart:io' show Platform;
import 'package:conduit/l10n/app_localizations.dart'; import 'package:conduit/l10n/app_localizations.dart';
import '../services/file_attachment_service.dart'; import '../services/file_attachment_service.dart';
@@ -75,10 +74,7 @@ class _FileAttachmentCard extends ConsumerWidget {
children: [ children: [
Row( Row(
children: [ children: [
Text( Text(fileState.fileIcon, style: const TextStyle(fontSize: 20)),
fileState.fileIcon,
style: const TextStyle(fontSize: 20),
),
const Spacer(), const Spacer(),
_buildStatusIcon(context), _buildStatusIcon(context),
], ],
@@ -225,10 +221,7 @@ class MessageAttachmentPreview extends StatelessWidget {
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
const Text( const Text('📎', style: TextStyle(fontSize: 14)),
'📎',
style: TextStyle(fontSize: 14),
),
const SizedBox(width: Spacing.xs), const SizedBox(width: Spacing.xs),
Text( Text(
AppLocalizations.of(context)!.attachmentLabel, AppLocalizations.of(context)!.attachmentLabel,

View File

@@ -5,7 +5,6 @@ import 'enhanced_attachment.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_animate/flutter_animate.dart';
import 'dart:io' show Platform; import 'dart:io' show Platform;
import 'package:conduit/l10n/app_localizations.dart'; import 'package:conduit/l10n/app_localizations.dart';
import 'package:conduit/shared/widgets/chat_action_button.dart'; import 'package:conduit/shared/widgets/chat_action_button.dart';
@@ -149,13 +148,6 @@ class _UserMessageBubbleState extends ConsumerState<UserMessageBubble>
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(
AppBorderRadius.messageBubble, AppBorderRadius.messageBubble,
), ),
boxShadow: [
BoxShadow(
color: context.conduitTheme.cardShadow.withValues(alpha: 0.1),
blurRadius: 6,
offset: const Offset(0, 2),
),
],
), ),
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(
@@ -196,15 +188,6 @@ class _UserMessageBubbleState extends ConsumerState<UserMessageBubble>
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(
AppBorderRadius.messageBubble, AppBorderRadius.messageBubble,
), ),
boxShadow: [
BoxShadow(
color: context.conduitTheme.cardShadow.withValues(
alpha: 0.08,
),
blurRadius: 4,
offset: const Offset(0, 1),
),
],
), ),
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(
@@ -248,15 +231,6 @@ class _UserMessageBubbleState extends ConsumerState<UserMessageBubble>
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(AppBorderRadius.md), borderRadius: BorderRadius.circular(AppBorderRadius.md),
boxShadow: [
BoxShadow(
color: context.conduitTheme.cardShadow.withValues(
alpha: 0.06,
),
blurRadius: 3,
offset: const Offset(0, 1),
),
],
), ),
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular(AppBorderRadius.md), borderRadius: BorderRadius.circular(AppBorderRadius.md),
@@ -294,13 +268,6 @@ class _UserMessageBubbleState extends ConsumerState<UserMessageBubble>
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(
AppBorderRadius.messageBubble, AppBorderRadius.messageBubble,
), ),
boxShadow: [
BoxShadow(
color: context.conduitTheme.cardShadow.withValues(alpha: 0.1),
blurRadius: 6,
offset: const Offset(0, 2),
),
],
), ),
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(
@@ -341,15 +308,6 @@ class _UserMessageBubbleState extends ConsumerState<UserMessageBubble>
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(
AppBorderRadius.messageBubble, AppBorderRadius.messageBubble,
), ),
boxShadow: [
BoxShadow(
color: context.conduitTheme.cardShadow.withValues(
alpha: 0.08,
),
blurRadius: 4,
offset: const Offset(0, 1),
),
],
), ),
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(
@@ -390,15 +348,6 @@ class _UserMessageBubbleState extends ConsumerState<UserMessageBubble>
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(AppBorderRadius.md), borderRadius: BorderRadius.circular(AppBorderRadius.md),
boxShadow: [
BoxShadow(
color: context.conduitTheme.cardShadow.withValues(
alpha: 0.06,
),
blurRadius: 3,
offset: const Offset(0, 1),
),
],
), ),
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular(AppBorderRadius.md), borderRadius: BorderRadius.circular(AppBorderRadius.md),
@@ -509,173 +458,148 @@ class _UserMessageBubbleState extends ConsumerState<UserMessageBubble>
); );
return GestureDetector( return GestureDetector(
onLongPress: () => _toggleActions(), onLongPress: () => _toggleActions(),
behavior: HitTestBehavior.translucent, behavior: HitTestBehavior.translucent,
child: Container( child: Container(
width: double.infinity, width: double.infinity,
margin: const EdgeInsets.only( margin: const EdgeInsets.only(
bottom: Spacing.md, bottom: Spacing.md,
left: Spacing.xxxl, left: Spacing.xxxl,
right: Spacing.xs, right: Spacing.xs,
), ),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
// Display images outside and above the text bubble (iMessage style) // Display images outside and above the text bubble (iMessage style)
// Prioritize files array over attachmentIds to avoid duplication // Prioritize files array over attachmentIds to avoid duplication
if (hasFilesFromArray) ...[ if (hasFilesFromArray) ...[
_buildUserFileImages(), _buildUserFileImages(),
] else if (hasImages) ...[ ] else if (hasImages) ...[
_buildUserAttachmentImages(), _buildUserAttachmentImages(),
], ],
// Display text bubble if there's text content // Display text bubble if there's text content
if (hasText) const SizedBox(height: Spacing.xs), if (hasText) const SizedBox(height: Spacing.xs),
if (hasText) if (hasText)
Row( Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [
Flexible( Flexible(
child: ConstrainedBox( child: ConstrainedBox(
constraints: BoxConstraints( constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width * 0.82, 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( border: Border.all(
padding: const EdgeInsets.symmetric( color: context.conduitTheme.chatBubbleUserBorder
horizontal: Spacing.chatBubblePadding, .withValues(alpha: 0.5),
vertical: Spacing.sm, width: BorderWidth.standard,
),
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 <String>[],
style: AppTypography
.chatMessageStyle
.copyWith(
color:
inlineEditTextColor,
),
decoration:
const BoxDecoration(),
cursorColor: context
.conduitTheme
.buttonPrimary,
onSubmitted: (_) =>
_saveInlineEdit(),
)
: TextField(
controller: _editController,
maxLines: null,
autofillHints: const <String>[],
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,
),
),
), ),
), ),
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 <String>[],
style: AppTypography
.chatMessageStyle
.copyWith(
color: inlineEditTextColor,
),
decoration: const BoxDecoration(),
cursorColor: context
.conduitTheme
.buttonPrimary,
onSubmitted: (_) =>
_saveInlineEdit(),
)
: TextField(
controller: _editController,
maxLines: null,
autofillHints: const <String>[],
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(),
], ],
], ),
), if (hasText) const SizedBox(height: Spacing.xs),
),
) // Action buttons below the message
.animate() if (_showActions) ...[
.fadeIn(duration: AnimationDuration.messageAppear) const SizedBox(height: Spacing.sm),
.slideX( _buildUserActionButtons(),
begin: AnimationValues.messageSlideDistance, ],
end: 0, ],
duration: AnimationDuration.messageSlide, ),
curve: AnimationCurves.messageSlide, ),
); );
} }
// Assistant-only message renderer removed. // Assistant-only message renderer removed.

View File

@@ -565,16 +565,19 @@ class _ChatsDrawerState extends ConsumerState<ChatsDrawer> {
children: [ children: [
Text( Text(
title, title,
style: AppTypography.labelStyle.copyWith(color: theme.textSecondary), style: AppTypography.labelStyle.copyWith(
color: theme.textSecondary,
fontWeight: FontWeight.w600,
),
), ),
const SizedBox(width: Spacing.xs), const SizedBox(width: Spacing.xs),
Container( Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
decoration: BoxDecoration( decoration: BoxDecoration(
color: theme.surfaceContainer.withValues(alpha: 0.6), color: theme.surfaceContainer.withValues(alpha: 0.4),
borderRadius: BorderRadius.circular(AppBorderRadius.xs), borderRadius: BorderRadius.circular(AppBorderRadius.xs),
border: Border.all( border: Border.all(
color: theme.dividerColor, color: theme.dividerColor.withValues(alpha: 0.5),
width: BorderWidth.thin, width: BorderWidth.thin,
), ),
), ),
@@ -1029,18 +1032,15 @@ class _ChatsDrawerState extends ConsumerState<ChatsDrawer> {
color: isHover color: isHover
? theme.buttonPrimary.withValues(alpha: 0.08) ? theme.buttonPrimary.withValues(alpha: 0.08)
: theme.surfaceContainer.withValues(alpha: 0.03), : theme.surfaceContainer.withValues(alpha: 0.03),
borderRadius: BorderRadius.circular(AppBorderRadius.md), borderRadius: BorderRadius.circular(AppBorderRadius.small),
border: Border.all( border: Border.all(
color: isHover color: isHover
? theme.buttonPrimary.withValues(alpha: 0.6) ? theme.buttonPrimary.withValues(alpha: 0.5)
: theme.dividerColor, : theme.dividerColor.withValues(alpha: 0.5),
width: BorderWidth.regular, width: BorderWidth.standard,
), ),
), ),
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.all(Spacing.sm),
horizontal: Spacing.md,
vertical: Spacing.sm,
),
child: Row( child: Row(
children: [ children: [
Icon( Icon(
@@ -1048,14 +1048,15 @@ class _ChatsDrawerState extends ConsumerState<ChatsDrawer> {
? CupertinoIcons.folder_badge_minus ? CupertinoIcons.folder_badge_minus
: Icons.folder_off_outlined, : Icons.folder_off_outlined,
color: theme.iconPrimary, color: theme.iconPrimary,
size: IconSize.small,
), ),
const SizedBox(width: Spacing.sm), const SizedBox(width: Spacing.sm),
Expanded( Expanded(
child: Text( child: Text(
'Drop here to remove from folder', 'Drop here to remove from folder',
style: AppTypography.bodyMediumStyle.copyWith( style: AppTypography.bodySmallStyle.copyWith(
color: theme.textPrimary, color: theme.textPrimary,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w500,
), ),
), ),
), ),
@@ -1351,55 +1352,46 @@ class _ChatsDrawerState extends ConsumerState<ChatsDrawer> {
if (user != null) ...[ if (user != null) ...[
const SizedBox(height: Spacing.sm), const SizedBox(height: Spacing.sm),
Container( Container(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.all(Spacing.sm),
horizontal: Spacing.sm,
vertical: Spacing.xs,
),
decoration: BoxDecoration( decoration: BoxDecoration(
color: theme.surfaceContainer.withValues(alpha: 0.05), color: theme.surfaceContainer.withValues(alpha: 0.3),
borderRadius: BorderRadius.circular(AppBorderRadius.md), borderRadius: BorderRadius.circular(AppBorderRadius.small),
border: Border.all( border: Border.all(
color: theme.dividerColor, color: theme.dividerColor.withValues(alpha: 0.5),
width: BorderWidth.regular, width: BorderWidth.standard,
), ),
boxShadow: ConduitShadows.card(context),
), ),
child: Row( child: Row(
children: [ children: [
Container( Container(
width: IconSize.xl, width: 36,
height: IconSize.xl, height: 36,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(
AppBorderRadius.avatar, AppBorderRadius.avatar,
), ),
border: Border.all( border: Border.all(
color: theme.buttonPrimary.withValues(alpha: 0.35), color: theme.buttonPrimary.withValues(alpha: 0.25),
width: BorderWidth.thin, width: BorderWidth.thin,
), ),
), ),
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
child: UserAvatar( child: UserAvatar(
size: IconSize.xl, size: 36,
imageUrl: avatarUrl, imageUrl: avatarUrl,
fallbackText: initial, fallbackText: initial,
), ),
), ),
const SizedBox(width: Spacing.xs), const SizedBox(width: Spacing.sm),
Expanded( Expanded(
child: Column( child: Text(
crossAxisAlignment: CrossAxisAlignment.start, displayName,
children: [ maxLines: 1,
Text( overflow: TextOverflow.ellipsis,
displayName, style: AppTypography.bodySmallStyle.copyWith(
maxLines: 1, color: theme.textPrimary,
overflow: TextOverflow.ellipsis, fontWeight: FontWeight.w600,
style: AppTypography.bodySmallStyle.copyWith( ),
color: theme.textPrimary,
fontWeight: FontWeight.w600,
),
),
],
), ),
), ),
IconButton( IconButton(
@@ -1408,12 +1400,13 @@ class _ChatsDrawerState extends ConsumerState<ChatsDrawer> {
Navigator.of(context).maybePop(); Navigator.of(context).maybePop();
context.pushNamed(RouteNames.profile); context.pushNamed(RouteNames.profile);
}, },
visualDensity: VisualDensity.compact,
icon: Icon( icon: Icon(
Platform.isIOS Platform.isIOS
? CupertinoIcons.settings ? CupertinoIcons.settings
: Icons.settings_rounded, : Icons.settings_rounded,
color: theme.iconSecondary, color: theme.iconSecondary,
size: IconSize.listItem, size: IconSize.small,
), ),
), ),
], ],
@@ -1621,19 +1614,14 @@ class _ConversationTile extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = context.conduitTheme; final theme = context.conduitTheme;
final brightness = Theme.of(context).brightness;
final borderRadius = BorderRadius.zero; final borderRadius = BorderRadius.zero;
final Color background = selected final Color background = selected
? theme.buttonPrimary.withValues( ? theme.buttonPrimary.withValues(alpha: 0.1)
alpha: brightness == Brightness.dark ? 0.28 : 0.16,
)
: theme.surfaceContainer; : theme.surfaceContainer;
final Color borderColor = selected final Color borderColor = selected
? theme.buttonPrimary.withValues(alpha: 0.7) ? theme.buttonPrimary.withValues(alpha: 0.5)
: theme.surfaceContainerHighest.withValues(alpha: 0.40); : theme.surfaceContainerHighest.withValues(alpha: 0.40);
final List<BoxShadow> shadow = selected final List<BoxShadow> shadow = const [];
? ConduitShadows.low(context)
: const [];
Color? overlayForStates(Set<WidgetState> states) { Color? overlayForStates(Set<WidgetState> states) {
if (states.contains(WidgetState.pressed)) { if (states.contains(WidgetState.pressed)) {

View File

@@ -598,7 +598,7 @@ class _PaletteOption extends StatelessWidget {
return InkWell( return InkWell(
onTap: onSelect, onTap: onSelect,
borderRadius: BorderRadius.circular(AppBorderRadius.md), borderRadius: BorderRadius.circular(AppBorderRadius.small),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(vertical: Spacing.sm), padding: const EdgeInsets.symmetric(vertical: Spacing.sm),
child: Row( child: Row(
@@ -607,7 +607,7 @@ class _PaletteOption extends StatelessWidget {
Icon( Icon(
isSelected ? Icons.radio_button_checked : Icons.radio_button_off, isSelected ? Icons.radio_button_checked : Icons.radio_button_off,
color: isSelected ? theme.buttonPrimary : theme.iconSecondary, color: isSelected ? theme.buttonPrimary : theme.iconSecondary,
size: IconSize.md, size: IconSize.small,
), ),
const SizedBox(width: Spacing.sm), const SizedBox(width: Spacing.sm),
Expanded( Expanded(
@@ -635,7 +635,7 @@ class _PaletteOption extends StatelessWidget {
child: Icon( child: Icon(
Icons.check_circle, Icons.check_circle,
color: theme.buttonPrimary, color: theme.buttonPrimary,
size: IconSize.sm, size: IconSize.small,
), ),
), ),
], ],
@@ -674,14 +674,14 @@ class _PaletteColorDot extends StatelessWidget {
final theme = context.conduitTheme; final theme = context.conduitTheme;
return Container( return Container(
margin: const EdgeInsets.only(right: Spacing.xs), margin: const EdgeInsets.only(right: Spacing.xs),
width: 20, width: 18,
height: 20, height: 18,
decoration: BoxDecoration( decoration: BoxDecoration(
color: color, color: color,
shape: BoxShape.circle, shape: BoxShape.circle,
border: Border.all( border: Border.all(
color: theme.dividerColor.withValues(alpha: 0.4), color: theme.dividerColor.withValues(alpha: 0.3),
width: 1.2, width: BorderWidth.thin,
), ),
), ),
); );

View File

@@ -3,7 +3,6 @@ import 'package:flutter/services.dart';
import '../../../shared/theme/theme_extensions.dart'; import '../../../shared/theme/theme_extensions.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_animate/flutter_animate.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:package_info_plus/package_info_plus.dart'; import 'package:package_info_plus/package_info_plus.dart';
import 'package:url_launcher/url_launcher_string.dart'; import 'package:url_launcher/url_launcher_string.dart';
@@ -306,11 +305,7 @@ class ProfilePage extends ConsumerWidget {
Row( Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
UserAvatar( UserAvatar(size: 56, imageUrl: avatarUrl, fallbackText: initial),
size: 56,
imageUrl: avatarUrl,
fallbackText: initial,
),
const SizedBox(width: Spacing.md), const SizedBox(width: Spacing.md),
Expanded( Expanded(
child: Column( child: Column(
@@ -1187,7 +1182,8 @@ class _DefaultModelBottomSheetState
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
), ),
), ),
] else if (model.isMultimodal || _modelSupportsReasoning(model)) ...[ ] else if (model.isMultimodal ||
_modelSupportsReasoning(model)) ...[
const SizedBox(height: Spacing.xs), const SizedBox(height: Spacing.xs),
Row( Row(
children: [ children: [