refactor: update spacing and styling in authentication and server connection pages

- Adjusted spacing values in the authentication and server connection pages for improved layout consistency.
- Modified container dimensions and padding to enhance visual appeal and maintain a cohesive design.
- Updated text styles to ensure better readability and alignment with the overall theme.
- Streamlined widget structures by removing unnecessary animations, focusing on performance and clarity.
- Enhanced the user interface by refining the design of buttons and form fields for a more polished experience.
This commit is contained in:
cogwheel0
2025-10-05 00:29:27 +05:30
parent 8629e1e039
commit 8cb55edab6
5 changed files with 461 additions and 684 deletions

View File

@@ -160,13 +160,13 @@ class _AuthenticationPageState extends ConsumerState<AuthenticationPage> {
// Header with progress indicator // Header with progress indicator
_buildHeader(), _buildHeader(),
const SizedBox(height: Spacing.extraLarge), const SizedBox(height: Spacing.xl),
// Main content // Main content
Expanded( Expanded(
child: SingleChildScrollView( child: SingleChildScrollView(
child: ConstrainedBox( child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 500), constraints: const BoxConstraints(maxWidth: 480),
child: Form( child: Form(
key: _formKey, key: _formKey,
child: Column( child: Column(
@@ -175,12 +175,12 @@ class _AuthenticationPageState extends ConsumerState<AuthenticationPage> {
// Server connection status // Server connection status
_buildServerStatus(), _buildServerStatus(),
const SizedBox(height: Spacing.sectionGap), const SizedBox(height: Spacing.xl),
// Welcome section // Welcome section
_buildWelcomeSection(), _buildWelcomeSection(),
const SizedBox(height: Spacing.sectionGap), const SizedBox(height: Spacing.xl),
// Authentication form // Authentication form
_buildAuthForm(), _buildAuthForm(),
@@ -214,8 +214,8 @@ class _AuthenticationPageState extends ConsumerState<AuthenticationPage> {
Row( Row(
children: [ children: [
Container( Container(
width: 32, width: 24,
height: 6, height: 4,
decoration: BoxDecoration( decoration: BoxDecoration(
color: context.conduitTheme.buttonPrimary, color: context.conduitTheme.buttonPrimary,
borderRadius: BorderRadius.circular(AppBorderRadius.round), borderRadius: BorderRadius.circular(AppBorderRadius.round),
@@ -223,8 +223,8 @@ class _AuthenticationPageState extends ConsumerState<AuthenticationPage> {
), ),
const SizedBox(width: Spacing.xs), const SizedBox(width: Spacing.xs),
Container( Container(
width: 32, width: 24,
height: 6, height: 4,
decoration: BoxDecoration( decoration: BoxDecoration(
color: context.conduitTheme.buttonPrimary, color: context.conduitTheme.buttonPrimary,
borderRadius: BorderRadius.circular(AppBorderRadius.round), borderRadius: BorderRadius.circular(AppBorderRadius.round),
@@ -251,43 +251,40 @@ class _AuthenticationPageState extends ConsumerState<AuthenticationPage> {
} catch (_) {} } catch (_) {}
return 'Server'; return 'Server';
}(); }();
return ConduitCard( return Container(
isElevated: false, padding: const EdgeInsets.symmetric(
padding: const EdgeInsets.all(Spacing.lg), horizontal: Spacing.md,
vertical: Spacing.sm,
),
decoration: BoxDecoration(
color: context.conduitTheme.success.withValues(alpha: 0.08),
borderRadius: BorderRadius.circular(AppBorderRadius.small),
border: Border.all(
color: context.conduitTheme.success.withValues(alpha: 0.2),
width: BorderWidth.standard,
),
),
child: Row( child: Row(
children: [ children: [
Container( Icon(
width: 40, Platform.isIOS
height: 40, ? CupertinoIcons.checkmark_circle
decoration: BoxDecoration( : Icons.check_circle_outline,
color: context.conduitTheme.successBackground, color: context.conduitTheme.success,
borderRadius: BorderRadius.circular(AppBorderRadius.round), size: IconSize.small,
border: Border.all(
color: context.conduitTheme.success.withValues(alpha: 0.3),
width: BorderWidth.standard,
),
),
child: Icon(
Platform.isIOS
? CupertinoIcons.checkmark_circle_fill
: Icons.check_circle,
color: context.conduitTheme.success,
size: IconSize.medium,
),
), ),
const SizedBox(width: Spacing.md), const SizedBox(width: Spacing.sm),
Expanded( Expanded(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
AppLocalizations.of(context)!.connectedToServer, AppLocalizations.of(context)!.connectedToServer,
style: context.conduitTheme.bodyMedium?.copyWith( style: context.conduitTheme.bodySmall?.copyWith(
fontWeight: FontWeight.w600, fontWeight: FontWeight.w500,
color: context.conduitTheme.success, color: context.conduitTheme.success,
), ),
), ),
const SizedBox(height: Spacing.xs),
Text( Text(
hostText, hostText,
style: context.conduitTheme.bodySmall?.copyWith( style: context.conduitTheme.bodySmall?.copyWith(
@@ -300,10 +297,6 @@ class _AuthenticationPageState extends ConsumerState<AuthenticationPage> {
), ),
], ],
), ),
).animate().slideX(
begin: -0.05,
duration: AnimationDuration.messageSlide,
curve: Curves.easeOutCubic,
); );
} }
@@ -312,73 +305,60 @@ class _AuthenticationPageState extends ConsumerState<AuthenticationPage> {
children: [ children: [
BrandService.createBrandIcon( BrandService.createBrandIcon(
size: 48, size: 48,
useGradient: true, useGradient: false,
addShadow: true, addShadow: false,
context: context, context: context,
).animate().scale(
duration: AnimationDuration.pageTransition,
curve: Curves.easeOutBack,
), ),
const SizedBox(height: Spacing.lg), const SizedBox(height: Spacing.lg),
Text( Text(
AppLocalizations.of(context)!.signIn, AppLocalizations.of(context)!.signIn,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: context.conduitTheme.headingLarge?.copyWith( style: context.conduitTheme.headingLarge?.copyWith(
fontWeight: FontWeight.w700, fontWeight: FontWeight.w600,
height: 1.2, height: 1.3,
), ),
).animate().fadeIn(
duration: AnimationDuration.pageTransition,
delay: AnimationDuration.microInteraction,
), ),
const SizedBox(height: Spacing.sm), const SizedBox(height: Spacing.sm),
Text( Text(
AppLocalizations.of(context)!.enterCredentials, AppLocalizations.of(context)!.enterCredentials,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: context.conduitTheme.bodyLarge?.copyWith( style: context.conduitTheme.bodyMedium?.copyWith(
color: context.conduitTheme.textSecondary, color: context.conduitTheme.textSecondary,
height: 1.5, height: 1.4,
), ),
).animate().fadeIn(
duration: AnimationDuration.pageTransition,
delay: AnimationDuration.fast,
), ),
], ],
); );
} }
Widget _buildAuthForm() { Widget _buildAuthForm() {
return ConduitCard( return Column(
isElevated: true, crossAxisAlignment: CrossAxisAlignment.stretch,
padding: const EdgeInsets.all(Spacing.xl), children: [
child: Column( // Authentication mode toggle
crossAxisAlignment: CrossAxisAlignment.stretch, _buildAuthModeToggle(),
children: [
// Authentication mode toggle
_buildAuthModeToggle(),
const SizedBox(height: Spacing.lg), const SizedBox(height: Spacing.lg),
// Authentication form fields // Authentication form fields
_buildAuthFields(), _buildAuthFields(),
if (_loginError != null) ...[ if (_loginError != null) ...[
const SizedBox(height: Spacing.md), const SizedBox(height: Spacing.md),
_buildErrorMessage(_loginError!), _buildErrorMessage(_loginError!),
],
], ],
), ],
); );
} }
Widget _buildAuthModeToggle() { Widget _buildAuthModeToggle() {
return Container( return Container(
padding: const EdgeInsets.all(4), padding: const EdgeInsets.all(3),
decoration: BoxDecoration( decoration: BoxDecoration(
color: context.conduitTheme.surfaceContainer, color: context.conduitTheme.surfaceContainer.withValues(alpha: 0.5),
borderRadius: BorderRadius.circular(AppBorderRadius.button), borderRadius: BorderRadius.circular(AppBorderRadius.small),
border: Border.all( border: Border.all(
color: context.conduitTheme.dividerColor, color: context.conduitTheme.dividerColor.withValues(alpha: 0.5),
width: BorderWidth.standard, width: BorderWidth.standard,
), ),
), ),
@@ -406,9 +386,6 @@ class _AuthenticationPageState extends ConsumerState<AuthenticationPage> {
), ),
], ],
), ),
).animate().fadeIn(
duration: AnimationDuration.pageTransition,
delay: AnimationDuration.microInteraction,
); );
} }
@@ -425,13 +402,13 @@ class _AuthenticationPageState extends ConsumerState<AuthenticationPage> {
color: isSelected color: isSelected
? context.conduitTheme.buttonPrimary ? context.conduitTheme.buttonPrimary
: Colors.transparent, : Colors.transparent,
borderRadius: BorderRadius.circular(AppBorderRadius.button - 2), borderRadius: BorderRadius.circular(AppBorderRadius.small - 1),
child: InkWell( child: InkWell(
onTap: onTap, onTap: onTap,
borderRadius: BorderRadius.circular(AppBorderRadius.button - 2), borderRadius: BorderRadius.circular(AppBorderRadius.small - 1),
child: Container( child: Container(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
vertical: Spacing.md, vertical: Spacing.sm,
horizontal: Spacing.sm, horizontal: Spacing.sm,
), ),
child: Row( child: Row(
@@ -444,10 +421,10 @@ class _AuthenticationPageState extends ConsumerState<AuthenticationPage> {
? context.conduitTheme.buttonPrimaryText ? context.conduitTheme.buttonPrimaryText
: context.conduitTheme.iconSecondary, : context.conduitTheme.iconSecondary,
), ),
const SizedBox(width: Spacing.sm), const SizedBox(width: Spacing.xs),
Text( Text(
label, label,
style: context.conduitTheme.bodyMedium?.copyWith( style: context.conduitTheme.bodySmall?.copyWith(
color: isSelected color: isSelected
? context.conduitTheme.buttonPrimaryText ? context.conduitTheme.buttonPrimaryText
: context.conduitTheme.textSecondary, : context.conduitTheme.textSecondary,
@@ -590,25 +567,21 @@ class _AuthenticationPageState extends ConsumerState<AuthenticationPage> {
Widget _buildSignInButton() { Widget _buildSignInButton() {
return Padding( return Padding(
padding: const EdgeInsets.only(top: Spacing.lg), padding: const EdgeInsets.only(top: Spacing.lg),
child: child: ConduitButton(
ConduitButton( text: _isSigningIn
text: _isSigningIn ? AppLocalizations.of(context)!.signingIn
? AppLocalizations.of(context)!.signingIn : _useApiKey
: _useApiKey ? AppLocalizations.of(context)!.signInWithApiKey
? AppLocalizations.of(context)!.signInWithApiKey : AppLocalizations.of(context)!.signIn,
: AppLocalizations.of(context)!.signIn, icon: _isSigningIn
icon: _isSigningIn ? null
? null : (Platform.isIOS
: (Platform.isIOS ? CupertinoIcons.arrow_right
? CupertinoIcons.arrow_right : Icons.arrow_forward),
: Icons.arrow_forward), onPressed: _isSigningIn ? null : _signIn,
onPressed: _isSigningIn ? null : _signIn, isLoading: _isSigningIn,
isLoading: _isSigningIn, isFullWidth: true,
isFullWidth: true, ),
).animate().fadeIn(
duration: AnimationDuration.pageTransition,
delay: AnimationDuration.fast,
),
); );
} }
@@ -619,10 +592,10 @@ class _AuthenticationPageState extends ConsumerState<AuthenticationPage> {
child: Container( child: Container(
padding: const EdgeInsets.all(Spacing.md), padding: const EdgeInsets.all(Spacing.md),
decoration: BoxDecoration( decoration: BoxDecoration(
color: context.conduitTheme.errorBackground, color: context.conduitTheme.error.withValues(alpha: 0.08),
borderRadius: BorderRadius.circular(AppBorderRadius.button), borderRadius: BorderRadius.circular(AppBorderRadius.small),
border: Border.all( border: Border.all(
color: context.conduitTheme.error.withValues(alpha: 0.3), color: context.conduitTheme.error.withValues(alpha: 0.2),
width: BorderWidth.standard, width: BorderWidth.standard,
), ),
), ),
@@ -630,16 +603,16 @@ class _AuthenticationPageState extends ConsumerState<AuthenticationPage> {
children: [ children: [
Icon( Icon(
Platform.isIOS Platform.isIOS
? CupertinoIcons.exclamationmark_circle_fill ? CupertinoIcons.exclamationmark_circle
: Icons.error_outline, : Icons.error_outline,
color: context.conduitTheme.error, color: context.conduitTheme.error,
size: IconSize.medium, size: IconSize.small,
), ),
const SizedBox(width: Spacing.md), const SizedBox(width: Spacing.sm),
Expanded( Expanded(
child: Text( child: Text(
message, message,
style: context.conduitTheme.bodyMedium?.copyWith( style: context.conduitTheme.bodySmall?.copyWith(
color: context.conduitTheme.error, color: context.conduitTheme.error,
), ),
), ),
@@ -647,10 +620,6 @@ class _AuthenticationPageState extends ConsumerState<AuthenticationPage> {
], ],
), ),
), ),
).animate().slideX(
begin: 0.05,
duration: AnimationDuration.messageSlide,
curve: Curves.easeOutCubic,
); );
} }
} }

View File

@@ -231,13 +231,13 @@ class _ServerConnectionPageState extends ConsumerState<ServerConnectionPage> {
// Header with progress indicator // Header with progress indicator
_buildHeader(), _buildHeader(),
const SizedBox(height: Spacing.extraLarge), const SizedBox(height: Spacing.xl),
// Main content // Main content
Expanded( Expanded(
child: SingleChildScrollView( child: SingleChildScrollView(
child: ConstrainedBox( child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 500), constraints: const BoxConstraints(maxWidth: 480),
child: Form( child: Form(
key: _formKey, key: _formKey,
child: Column( child: Column(
@@ -246,17 +246,17 @@ class _ServerConnectionPageState extends ConsumerState<ServerConnectionPage> {
// Brand header // Brand header
_buildBrandHeader(reviewerMode), _buildBrandHeader(reviewerMode),
const SizedBox(height: Spacing.sectionGap), const SizedBox(height: Spacing.xl),
// Welcome section // Welcome section
_buildWelcomeSection(), _buildWelcomeSection(),
const SizedBox(height: Spacing.sectionGap), const SizedBox(height: Spacing.xl),
// Reviewer mode demo (if enabled) // Reviewer mode demo (if enabled)
if (reviewerMode) ...[ if (reviewerMode) ...[
_buildReviewerModeSection(), _buildReviewerModeSection(),
const SizedBox(height: Spacing.sectionGap), const SizedBox(height: Spacing.xl),
], ],
// Server connection form // Server connection form
@@ -286,8 +286,8 @@ class _ServerConnectionPageState extends ConsumerState<ServerConnectionPage> {
Row( Row(
children: [ children: [
Container( Container(
width: 32, width: 24,
height: 6, height: 4,
decoration: BoxDecoration( decoration: BoxDecoration(
color: context.conduitTheme.buttonPrimary, color: context.conduitTheme.buttonPrimary,
borderRadius: BorderRadius.circular(AppBorderRadius.round), borderRadius: BorderRadius.circular(AppBorderRadius.round),
@@ -295,10 +295,10 @@ class _ServerConnectionPageState extends ConsumerState<ServerConnectionPage> {
), ),
const SizedBox(width: Spacing.xs), const SizedBox(width: Spacing.xs),
Container( Container(
width: 32, width: 24,
height: 6, height: 4,
decoration: BoxDecoration( decoration: BoxDecoration(
color: context.conduitTheme.dividerColor, color: context.conduitTheme.dividerColor.withValues(alpha: 0.3),
borderRadius: BorderRadius.circular(AppBorderRadius.round), borderRadius: BorderRadius.circular(AppBorderRadius.round),
), ),
), ),
@@ -325,59 +325,31 @@ class _ServerConnectionPageState extends ConsumerState<ServerConnectionPage> {
), ),
); );
}, },
child: Column( child: Stack(
alignment: Alignment.center,
children: [ children: [
Stack( // Brand logo
alignment: Alignment.center, BrandService.createBrandIcon(
children: [ size: 56,
// Glow effect useGradient: false,
Container( addShadow: false,
width: 120, context: context,
height: 120,
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: RadialGradient(
colors: [
context.conduitTheme.buttonPrimary.withValues(
alpha: 0.12,
),
context.conduitTheme.buttonPrimary.withValues(
alpha: 0.06,
),
Colors.transparent,
],
stops: const [0.0, 0.7, 1.0],
radius: 0.8,
),
),
),
// Brand logo
BrandService.createBrandIcon(
size: 64,
useGradient: true,
addShadow: true,
context: context,
),
// Reviewer mode badge
if (reviewerMode)
Positioned(
bottom: 0,
child: ConduitBadge(
text: AppLocalizations.of(context)!.demoBadge,
backgroundColor: context.conduitTheme.warning.withValues(
alpha: 0.15,
),
textColor: context.conduitTheme.warning,
isCompact: true,
),
),
],
), ),
// Reviewer mode badge
if (reviewerMode)
Positioned(
bottom: -4,
child: ConduitBadge(
text: AppLocalizations.of(context)!.demoBadge,
backgroundColor: context.conduitTheme.warning.withValues(
alpha: 0.15,
),
textColor: context.conduitTheme.warning,
isCompact: true,
),
),
], ],
), ),
).animate().scale(
duration: AnimationDuration.pageTransition,
curve: Curves.easeOutBack,
); );
} }
@@ -388,24 +360,18 @@ class _ServerConnectionPageState extends ConsumerState<ServerConnectionPage> {
AppLocalizations.of(context)!.connectToServer, AppLocalizations.of(context)!.connectToServer,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: context.conduitTheme.headingLarge?.copyWith( style: context.conduitTheme.headingLarge?.copyWith(
fontWeight: FontWeight.w700, fontWeight: FontWeight.w600,
height: 1.2, height: 1.3,
), ),
).animate().fadeIn(
duration: AnimationDuration.pageTransition,
delay: AnimationDuration.microInteraction,
), ),
const SizedBox(height: Spacing.sm), const SizedBox(height: Spacing.sm),
Text( Text(
AppLocalizations.of(context)!.enterServerAddress, AppLocalizations.of(context)!.enterServerAddress,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: context.conduitTheme.bodyLarge?.copyWith( style: context.conduitTheme.bodyMedium?.copyWith(
color: context.conduitTheme.textSecondary, color: context.conduitTheme.textSecondary,
height: 1.5, height: 1.4,
), ),
).animate().fadeIn(
duration: AnimationDuration.pageTransition,
delay: AnimationDuration.fast,
), ),
], ],
); );
@@ -464,205 +430,192 @@ class _ServerConnectionPageState extends ConsumerState<ServerConnectionPage> {
} }
Widget _buildServerForm() { Widget _buildServerForm() {
return ConduitCard( return Column(
isElevated: true, crossAxisAlignment: CrossAxisAlignment.stretch,
padding: const EdgeInsets.all(Spacing.xl), children: [
child: Column( AccessibleFormField(
crossAxisAlignment: CrossAxisAlignment.stretch, label: AppLocalizations.of(context)!.serverUrl,
children: [ hint: AppLocalizations.of(context)!.serverUrlHint,
AccessibleFormField( controller: _urlController,
label: AppLocalizations.of(context)!.serverUrl, validator: InputValidationService.combine([
hint: AppLocalizations.of(context)!.serverUrlHint, InputValidationService.validateRequired,
controller: _urlController, (value) =>
validator: InputValidationService.combine([ InputValidationService.validateUrl(value, required: true),
InputValidationService.validateRequired, ]),
(value) => keyboardType: TextInputType.url,
InputValidationService.validateUrl(value, required: true), semanticLabel: AppLocalizations.of(context)!.enterServerUrlSemantic,
]), onSubmitted: (_) => _connectToServer(),
keyboardType: TextInputType.url, prefixIcon: Icon(
semanticLabel: AppLocalizations.of(context)!.enterServerUrlSemantic, Platform.isIOS ? CupertinoIcons.globe : Icons.public,
onSubmitted: (_) => _connectToServer(), color: context.conduitTheme.iconSecondary,
prefixIcon: Icon(
Platform.isIOS ? CupertinoIcons.globe : Icons.public,
color: context.conduitTheme.iconSecondary,
),
autofillHints: const [AutofillHints.url],
isRequired: true,
).animate().slideX(
begin: -0.05,
duration: AnimationDuration.messageSlide,
delay: AnimationDuration.microInteraction,
curve: Curves.easeOutCubic,
), ),
autofillHints: const [AutofillHints.url],
isRequired: true,
),
if (_connectionError != null) ...[ if (_connectionError != null) ...[
const SizedBox(height: Spacing.md), const SizedBox(height: Spacing.md),
_buildErrorMessage(_connectionError!), _buildErrorMessage(_connectionError!),
],
const SizedBox(height: Spacing.lg),
// Advanced settings
_buildAdvancedSettings(),
], ],
),
const SizedBox(height: Spacing.lg),
// Advanced settings
_buildAdvancedSettings(),
],
); );
} }
Widget _buildAdvancedSettings() { Widget _buildAdvancedSettings() {
return Column( return Column(
children: [ children: [
ConduitCard( InkWell(
isElevated: false, onTap: () => setState(
padding: const EdgeInsets.all(Spacing.lg), () => _showAdvancedSettings = !_showAdvancedSettings,
child: Column( ),
children: [ borderRadius: BorderRadius.circular(AppBorderRadius.button),
InkWell( child: Padding(
onTap: () => setState( padding: const EdgeInsets.symmetric(
() => _showAdvancedSettings = !_showAdvancedSettings, horizontal: Spacing.md,
vertical: Spacing.sm,
),
child: Row(
children: [
Icon(
Platform.isIOS ? CupertinoIcons.gear_alt : Icons.settings,
color: context.conduitTheme.iconSecondary,
size: IconSize.small,
), ),
borderRadius: BorderRadius.circular(AppBorderRadius.button), const SizedBox(width: Spacing.sm),
child: Padding( Expanded(
padding: const EdgeInsets.symmetric(vertical: Spacing.sm), child: Text(
child: Row( AppLocalizations.of(context)!.advancedSettings,
children: [ style: context.conduitTheme.bodySmall?.copyWith(
Icon( color: context.conduitTheme.textSecondary,
Platform.isIOS ? CupertinoIcons.gear : Icons.tune, ),
color: context.conduitTheme.iconSecondary,
size: IconSize.medium,
),
const SizedBox(width: Spacing.md),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
AppLocalizations.of(context)!.advancedSettings,
style: context.conduitTheme.bodyMedium?.copyWith(
fontWeight: FontWeight.w600,
),
),
if (_customHeaders.isNotEmpty)
Text(
'${_customHeaders.length} custom header${_customHeaders.length != 1 ? 's' : ''}',
style: context.conduitTheme.bodySmall?.copyWith(
color: context.conduitTheme.textSecondary,
),
),
],
),
),
AnimatedRotation(
duration: AnimationDuration.microInteraction,
turns: _showAdvancedSettings ? 0.5 : 0,
child: Icon(
Platform.isIOS
? CupertinoIcons.chevron_down
: Icons.expand_more,
color: context.conduitTheme.iconSecondary,
),
),
],
), ),
), ),
), if (_customHeaders.isNotEmpty)
AnimatedSize( Padding(
duration: AnimationDuration.microInteraction, padding: const EdgeInsets.only(right: Spacing.sm),
curve: Curves.easeInOutCubic, child: ConduitBadge(
child: _showAdvancedSettings text: '${_customHeaders.length}',
? _buildAdvancedSettingsContent() backgroundColor: context.conduitTheme.buttonPrimary
: const SizedBox.shrink(), .withValues(alpha: 0.1),
), textColor: context.conduitTheme.buttonPrimary,
], isCompact: true,
),
),
AnimatedRotation(
duration: AnimationDuration.microInteraction,
turns: _showAdvancedSettings ? 0.5 : 0,
child: Icon(
Platform.isIOS
? CupertinoIcons.chevron_down
: Icons.expand_more,
color: context.conduitTheme.iconSecondary,
size: IconSize.small,
),
),
],
),
), ),
), ),
AnimatedSize(
duration: AnimationDuration.microInteraction,
curve: Curves.easeInOutCubic,
child: _showAdvancedSettings
? _buildAdvancedSettingsContent()
: const SizedBox.shrink(),
),
], ],
); );
} }
Widget _buildAdvancedSettingsContent() { Widget _buildAdvancedSettingsContent() {
return Column( return Padding(
children: [ padding: const EdgeInsets.all(Spacing.md),
const SizedBox(height: Spacing.lg), child: Column(
ConduitDivider(), crossAxisAlignment: CrossAxisAlignment.start,
const SizedBox(height: Spacing.lg), children: [
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text(
AppLocalizations.of(context)!.customHeaders,
style: context.conduitTheme.bodyMedium?.copyWith(
fontWeight: FontWeight.w600,
),
),
if (_customHeaders.isNotEmpty)
Text( Text(
'${_customHeaders.length}/10', AppLocalizations.of(context)!.customHeaders,
style: context.conduitTheme.bodySmall?.copyWith( style: context.conduitTheme.bodySmall?.copyWith(
color: _customHeaders.length >= 10 fontWeight: FontWeight.w500,
? context.conduitTheme.error
: context.conduitTheme.textSecondary,
), ),
), ),
], if (_customHeaders.isNotEmpty)
), Text(
const SizedBox(height: Spacing.xs), '${_customHeaders.length}/10',
Text( style: context.conduitTheme.bodySmall?.copyWith(
AppLocalizations.of(context)!.customHeadersDescription, color: _customHeaders.length >= 10
style: context.conduitTheme.bodySmall?.copyWith( ? context.conduitTheme.error
color: context.conduitTheme.textSecondary, : context.conduitTheme.textSecondary,
),
),
],
), ),
), const SizedBox(height: Spacing.xs),
const SizedBox(height: Spacing.md), Text(
Row( AppLocalizations.of(context)!.customHeadersDescription,
crossAxisAlignment: CrossAxisAlignment.end, style: context.conduitTheme.bodySmall?.copyWith(
children: [ color: context.conduitTheme.textSecondary,
Expanded( ),
flex: 2, ),
child: AccessibleFormField( const SizedBox(height: Spacing.md),
label: AppLocalizations.of(context)!.headerName, Row(
hint: 'X-Custom-Header', crossAxisAlignment: CrossAxisAlignment.end,
controller: _headerKeyController, children: [
validator: (value) => _validateHeaderKey(value ?? ''), Expanded(
semanticLabel: 'Enter header name', flex: 2,
isCompact: true, child: AccessibleFormField(
keyboardType: TextInputType.text, label: AppLocalizations.of(context)!.headerName,
hint: 'X-Custom-Header',
controller: _headerKeyController,
validator: (value) => _validateHeaderKey(value ?? ''),
semanticLabel: 'Enter header name',
isCompact: true,
keyboardType: TextInputType.text,
),
), ),
), const SizedBox(width: Spacing.sm),
const SizedBox(width: Spacing.md), Expanded(
Expanded( flex: 3,
flex: 3, child: AccessibleFormField(
child: AccessibleFormField( label: AppLocalizations.of(context)!.headerValue,
label: AppLocalizations.of(context)!.headerValue, hint: AppLocalizations.of(context)!.headerValueHint,
hint: AppLocalizations.of(context)!.headerValueHint, controller: _headerValueController,
controller: _headerValueController, validator: (value) => _validateHeaderValue(value ?? ''),
validator: (value) => _validateHeaderValue(value ?? ''), semanticLabel: 'Enter header value',
semanticLabel: 'Enter header value', isCompact: true,
isCompact: true, keyboardType: TextInputType.text,
keyboardType: TextInputType.text, ),
), ),
), const SizedBox(width: Spacing.sm),
const SizedBox(width: Spacing.md), 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, backgroundColor: _customHeaders.length >= 10
backgroundColor: _customHeaders.length >= 10 ? context.conduitTheme.surfaceContainer
? context.conduitTheme.surfaceContainer : context.conduitTheme.buttonPrimary,
: context.conduitTheme.buttonPrimary, iconColor: _customHeaders.length >= 10
iconColor: _customHeaders.length >= 10 ? context.conduitTheme.textDisabled
? context.conduitTheme.textDisabled : context.conduitTheme.buttonPrimaryText,
: context.conduitTheme.buttonPrimaryText, ),
), ],
),
if (_customHeaders.isNotEmpty) ...[
const SizedBox(height: Spacing.md),
_buildCustomHeadersList(),
], ],
),
if (_customHeaders.isNotEmpty) ...[
const SizedBox(height: Spacing.lg),
_buildCustomHeadersList(),
], ],
], ),
); );
} }
@@ -670,33 +623,32 @@ class _ServerConnectionPageState extends ConsumerState<ServerConnectionPage> {
return Column( return Column(
children: _customHeaders.entries.map((entry) { children: _customHeaders.entries.map((entry) {
return Container( return Container(
margin: const EdgeInsets.only(bottom: Spacing.sm), margin: const EdgeInsets.only(bottom: Spacing.xs),
padding: const EdgeInsets.all(Spacing.md), padding: const EdgeInsets.symmetric(
horizontal: Spacing.md,
vertical: Spacing.sm,
),
decoration: BoxDecoration( decoration: BoxDecoration(
color: context.conduitTheme.surfaceContainer.withValues(alpha: 0.5), color: context.conduitTheme.surfaceContainer.withValues(alpha: 0.3),
borderRadius: BorderRadius.circular(AppBorderRadius.button), borderRadius: BorderRadius.circular(AppBorderRadius.small),
border: Border.all( border: Border.all(
color: context.conduitTheme.dividerColor, color: context.conduitTheme.dividerColor.withValues(alpha: 0.5),
width: BorderWidth.standard, width: BorderWidth.standard,
), ),
), ),
child: Row( child: Row(
children: [ children: [
// Make the header badge flexible and truncate long text
Flexible( Flexible(
fit: FlexFit.loose, fit: FlexFit.loose,
child: ConduitBadge( child: Text(
text: entry.key, entry.key,
backgroundColor: context.conduitTheme.buttonPrimary style: context.conduitTheme.bodySmall?.copyWith(
.withValues(alpha: 0.1), fontWeight: FontWeight.w500,
textColor: context.conduitTheme.buttonPrimary, ),
isCompact: true,
maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
softWrap: false,
), ),
), ),
const SizedBox(width: Spacing.md), const SizedBox(width: Spacing.sm),
Expanded( Expanded(
child: Text( child: Text(
entry.value, entry.value,
@@ -707,20 +659,18 @@ class _ServerConnectionPageState extends ConsumerState<ServerConnectionPage> {
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
), ),
const SizedBox(width: Spacing.md), const SizedBox(width: Spacing.sm),
ConduitIconButton( ConduitIconButton(
icon: Platform.isIOS ? CupertinoIcons.xmark : Icons.close, icon: Platform.isIOS ? CupertinoIcons.xmark : Icons.close,
onPressed: () => _removeCustomHeader(entry.key), onPressed: () => _removeCustomHeader(entry.key),
tooltip: AppLocalizations.of(context)!.removeHeader, tooltip: AppLocalizations.of(context)!.removeHeader,
backgroundColor: context.conduitTheme.error.withValues( backgroundColor: Colors.transparent,
alpha: 0.1, iconColor: context.conduitTheme.textSecondary,
),
iconColor: context.conduitTheme.error,
isCompact: true, isCompact: true,
), ),
], ],
), ),
).animate().fadeIn(duration: AnimationDuration.microInteraction); );
}).toList(), }).toList(),
); );
} }
@@ -728,23 +678,19 @@ class _ServerConnectionPageState extends ConsumerState<ServerConnectionPage> {
Widget _buildConnectButton() { Widget _buildConnectButton() {
return Padding( return Padding(
padding: const EdgeInsets.only(top: Spacing.lg), padding: const EdgeInsets.only(top: Spacing.lg),
child: child: ConduitButton(
ConduitButton( text: _isConnecting
text: _isConnecting ? AppLocalizations.of(context)!.connecting
? AppLocalizations.of(context)!.connecting : AppLocalizations.of(context)!.connectToServerButton,
: AppLocalizations.of(context)!.connectToServerButton, icon: _isConnecting
icon: _isConnecting ? null
? null : (Platform.isIOS
: (Platform.isIOS ? CupertinoIcons.arrow_right
? CupertinoIcons.arrow_right : Icons.arrow_forward),
: Icons.arrow_forward), onPressed: _isConnecting ? null : _connectToServer,
onPressed: _isConnecting ? null : _connectToServer, isLoading: _isConnecting,
isLoading: _isConnecting, isFullWidth: true,
isFullWidth: true, ),
).animate().fadeIn(
duration: AnimationDuration.pageTransition,
delay: AnimationDuration.fast,
),
); );
} }
@@ -752,42 +698,37 @@ class _ServerConnectionPageState extends ConsumerState<ServerConnectionPage> {
return Semantics( return Semantics(
liveRegion: true, liveRegion: true,
label: message, label: message,
child: child: Container(
Container( padding: const EdgeInsets.all(Spacing.md),
padding: const EdgeInsets.all(Spacing.md), decoration: BoxDecoration(
decoration: BoxDecoration( color: context.conduitTheme.error.withValues(alpha: 0.08),
color: context.conduitTheme.errorBackground, borderRadius: BorderRadius.circular(AppBorderRadius.small),
borderRadius: BorderRadius.circular(AppBorderRadius.button), border: Border.all(
border: Border.all( color: context.conduitTheme.error.withValues(alpha: 0.2),
color: context.conduitTheme.error.withValues(alpha: 0.3), width: BorderWidth.standard,
width: BorderWidth.standard, ),
),
child: Row(
children: [
Icon(
Platform.isIOS
? CupertinoIcons.exclamationmark_circle
: Icons.error_outline,
color: context.conduitTheme.error,
size: IconSize.small,
),
const SizedBox(width: Spacing.sm),
Expanded(
child: Text(
message,
style: context.conduitTheme.bodySmall?.copyWith(
color: context.conduitTheme.error,
),
), ),
), ),
child: Row( ],
children: [ ),
Icon( ),
Platform.isIOS
? CupertinoIcons.exclamationmark_circle_fill
: Icons.error_outline,
color: context.conduitTheme.error,
size: IconSize.medium,
),
const SizedBox(width: Spacing.md),
Expanded(
child: Text(
message,
style: context.conduitTheme.bodyMedium?.copyWith(
color: context.conduitTheme.error,
),
),
),
],
),
).animate().slideX(
begin: 0.05,
duration: AnimationDuration.messageSlide,
curve: Curves.easeOutCubic,
),
); );
} }

View File

@@ -1991,39 +1991,27 @@ class _ModelSelectorSheetState extends ConsumerState<_ModelSelectorSheet> {
final iconUrl = resolveModelIconUrlForModel(api, model); final iconUrl = resolveModelIconUrlForModel(api, model);
return PressableScale( return PressableScale(
onTap: onTap, onTap: onTap,
borderRadius: BorderRadius.circular(AppBorderRadius.md), borderRadius: BorderRadius.circular(AppBorderRadius.small),
child: Container( child: Container(
margin: const EdgeInsets.only(bottom: Spacing.md), margin: const EdgeInsets.only(bottom: Spacing.sm),
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: isSelected
? LinearGradient(
colors: [
context.conduitTheme.buttonPrimary.withValues(alpha: 0.2),
context.conduitTheme.buttonPrimary.withValues(alpha: 0.1),
],
)
: null,
color: isSelected color: isSelected
? null ? context.conduitTheme.buttonPrimary.withValues(alpha: 0.1)
: context.conduitTheme.surfaceBackground.withValues(alpha: 0.05), : context.conduitTheme.surfaceBackground.withValues(alpha: 0.05),
borderRadius: BorderRadius.circular(AppBorderRadius.md), borderRadius: BorderRadius.circular(AppBorderRadius.small),
border: Border.all( border: Border.all(
color: isSelected color: isSelected
? context.conduitTheme.buttonPrimary.withValues(alpha: 0.5) ? context.conduitTheme.buttonPrimary.withValues(alpha: 0.3)
: context.conduitTheme.dividerColor, : context.conduitTheme.dividerColor.withValues(alpha: 0.5),
width: BorderWidth.regular, width: BorderWidth.standard,
), ),
boxShadow: isSelected ? ConduitShadows.card(context) : null,
), ),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.all(Spacing.sm),
horizontal: Spacing.md,
vertical: Spacing.sm,
),
child: Row( child: Row(
children: [ children: [
ModelAvatar(size: 32, imageUrl: iconUrl, label: model.name), ModelAvatar(size: 32, imageUrl: iconUrl, label: model.name),
const SizedBox(width: Spacing.md), const SizedBox(width: Spacing.sm),
Expanded( Expanded(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@@ -2038,65 +2026,42 @@ class _ModelSelectorSheetState extends ConsumerState<_ModelSelectorSheet> {
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
const SizedBox(height: Spacing.xs), if (model.isMultimodal || _modelSupportsReasoning(model)) ...[
Row( const SizedBox(height: Spacing.xs),
children: [ Row(
if (model.isMultimodal) children: [
_capabilityChip( if (model.isMultimodal)
icon: Platform.isIOS _capabilityChip(
? CupertinoIcons.photo icon: Platform.isIOS
: Icons.image, ? CupertinoIcons.photo
label: 'Multimodal', : Icons.image,
), label: 'Multimodal',
if (_modelSupportsReasoning(model)) ),
_capabilityChip( if (_modelSupportsReasoning(model))
icon: Platform.isIOS _capabilityChip(
? CupertinoIcons.lightbulb icon: Platform.isIOS
: Icons.psychology_alt, ? CupertinoIcons.lightbulb
label: 'Reasoning', : Icons.psychology_alt,
), label: 'Reasoning',
], ),
), ],
),
],
], ],
), ),
), ),
const SizedBox(width: Spacing.md), const SizedBox(width: Spacing.sm),
AnimatedOpacity( if (isSelected)
opacity: isSelected ? 1 : 0.6, Icon(
duration: AnimationDuration.fast, Platform.isIOS ? CupertinoIcons.check_mark : Icons.check,
child: Container( color: context.conduitTheme.buttonPrimary,
padding: const EdgeInsets.all(Spacing.xxs), size: IconSize.small,
decoration: BoxDecoration(
color: isSelected
? context.conduitTheme.buttonPrimary
: context.conduitTheme.surfaceBackground,
borderRadius: BorderRadius.circular(AppBorderRadius.md),
border: Border.all(
color: isSelected
? context.conduitTheme.buttonPrimary.withValues(
alpha: 0.6,
)
: context.conduitTheme.dividerColor,
),
),
child: Icon(
isSelected
? (Platform.isIOS
? CupertinoIcons.check_mark
: Icons.check)
: (Platform.isIOS ? CupertinoIcons.add : Icons.add),
color: isSelected
? context.conduitTheme.textInverse
: context.conduitTheme.iconSecondary,
size: 14,
),
), ),
),
], ],
), ),
), ),
), ),
).animate().fadeIn(duration: AnimationDuration.microInteraction); );
} }
// Intentionally left blank placeholder for nested helper; moved to top-level below // Intentionally left blank placeholder for nested helper; moved to top-level below

View File

@@ -62,9 +62,9 @@ class AppCustomizationPage extends ConsumerWidget {
settings, settings,
activePalette, activePalette,
), ),
const SizedBox(height: Spacing.sectionGap), const SizedBox(height: Spacing.xl),
_buildQuickPillsSection(context, ref, settings), _buildQuickPillsSection(context, ref, settings),
const SizedBox(height: Spacing.sectionGap), const SizedBox(height: Spacing.xl),
_buildChatSection(context, ref, settings), _buildChatSection(context, ref, settings),
], ],
), ),
@@ -170,7 +170,7 @@ class AppCustomizationPage extends ConsumerWidget {
final theme = context.conduitTheme; final theme = context.conduitTheme;
return ConduitCard( return ConduitCard(
padding: const EdgeInsets.all(Spacing.cardPadding), padding: const EdgeInsets.all(Spacing.md),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@@ -192,24 +192,17 @@ class AppCustomizationPage extends ConsumerWidget {
children: [ children: [
Text( Text(
AppLocalizations.of(context)!.darkMode, AppLocalizations.of(context)!.darkMode,
style: style: theme.bodyMedium?.copyWith(
theme.bodyLarge?.copyWith( color: theme.textPrimary,
color: theme.textPrimary, fontWeight: FontWeight.w600,
fontWeight: FontWeight.w600, ),
) ??
TextStyle(
color: theme.textPrimary,
fontWeight: FontWeight.w600,
),
), ),
const SizedBox(height: Spacing.textSpacing), const SizedBox(height: Spacing.xs),
Text( Text(
themeDescription, themeDescription,
style: style: theme.bodySmall?.copyWith(
theme.bodySmall?.copyWith( color: theme.textSecondary,
color: theme.textSecondary, ),
) ??
TextStyle(color: theme.textSecondary),
), ),
], ],
), ),
@@ -290,7 +283,7 @@ class AppCustomizationPage extends ConsumerWidget {
), ),
const SizedBox(height: Spacing.sm), const SizedBox(height: Spacing.sm),
ConduitCard( ConduitCard(
padding: const EdgeInsets.all(Spacing.cardPadding), padding: const EdgeInsets.all(Spacing.md),
child: Column( child: Column(
children: [ children: [
for (final palette in palettes) for (final palette in palettes)
@@ -387,7 +380,7 @@ class AppCustomizationPage extends ConsumerWidget {
), ),
const SizedBox(height: Spacing.sm), const SizedBox(height: Spacing.sm),
ConduitCard( ConduitCard(
padding: const EdgeInsets.all(Spacing.cardPadding), padding: const EdgeInsets.all(Spacing.md),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@@ -406,11 +399,9 @@ class AppCustomizationPage extends ConsumerWidget {
Expanded( Expanded(
child: Text( child: Text(
AppLocalizations.of(context)!.quickActionsDescription, AppLocalizations.of(context)!.quickActionsDescription,
style: style: theme.bodySmall?.copyWith(
theme.bodySmall?.copyWith( color: theme.textSecondary,
color: theme.textSecondary, ),
) ??
TextStyle(color: theme.textSecondary),
), ),
), ),
TextButton( TextButton(
@@ -514,18 +505,18 @@ class AppCustomizationPage extends ConsumerWidget {
required Color color, required Color color,
}) { }) {
return Container( return Container(
width: 48, width: 40,
height: 48, height: 40,
decoration: BoxDecoration( decoration: BoxDecoration(
color: color.withValues(alpha: Alpha.highlight), color: color.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(AppBorderRadius.medium), borderRadius: BorderRadius.circular(AppBorderRadius.small),
border: Border.all( border: Border.all(
color: color.withValues(alpha: 0.2), color: color.withValues(alpha: 0.2),
width: BorderWidth.thin, width: BorderWidth.thin,
), ),
), ),
alignment: Alignment.center, alignment: Alignment.center,
child: Icon(icon, color: color, size: IconSize.large), child: Icon(icon, color: color, size: IconSize.medium),
); );
} }
@@ -629,19 +620,12 @@ class _PaletteOption extends StatelessWidget {
Expanded( Expanded(
child: Text( child: Text(
palette.label, palette.label,
style: style: theme.bodyMedium?.copyWith(
theme.bodyLarge?.copyWith( color: theme.textPrimary,
color: theme.textPrimary, fontWeight: isSelected
fontWeight: isSelected ? FontWeight.w600
? FontWeight.w600 : FontWeight.w500,
: FontWeight.w500, ),
) ??
TextStyle(
color: theme.textPrimary,
fontWeight: isSelected
? FontWeight.w600
: FontWeight.w500,
),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
), ),
@@ -725,10 +709,7 @@ class _CustomizationTile extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = context.conduitTheme; final theme = context.conduitTheme;
return ConduitCard( return ConduitCard(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.all(Spacing.md),
horizontal: Spacing.listItemPadding,
vertical: Spacing.md,
),
onTap: onTap, onTap: onTap,
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
@@ -741,31 +722,24 @@ class _CustomizationTile extends StatelessWidget {
children: [ children: [
Text( Text(
title, title,
style: style: theme.bodyMedium?.copyWith(
theme.bodyLarge?.copyWith( color: theme.textPrimary,
color: theme.textPrimary, fontWeight: FontWeight.w600,
fontWeight: FontWeight.w600, ),
) ??
TextStyle(
color: theme.textPrimary,
fontWeight: FontWeight.w600,
),
), ),
const SizedBox(height: Spacing.textSpacing), const SizedBox(height: Spacing.xs),
Text( Text(
subtitle, subtitle,
style: style: theme.bodySmall?.copyWith(color: theme.textSecondary),
theme.bodySmall?.copyWith(color: theme.textSecondary) ??
TextStyle(color: theme.textSecondary),
), ),
], ],
), ),
), ),
if (trailing != null) ...[ if (trailing != null) ...[
const SizedBox(width: Spacing.md), const SizedBox(width: Spacing.sm),
trailing!, trailing!,
] else if (showChevron && onTap != null) ...[ ] else if (showChevron && onTap != null) ...[
const SizedBox(width: Spacing.md), const SizedBox(width: Spacing.sm),
Icon( Icon(
UiUtils.platformIcon( UiUtils.platformIcon(
ios: CupertinoIcons.chevron_right, ios: CupertinoIcons.chevron_right,

View File

@@ -144,38 +144,11 @@ class ProfilePage extends ConsumerWidget {
vertical: Spacing.pagePadding, vertical: Spacing.pagePadding,
), ),
children: [ children: [
_buildProfileHeader(context, userData, api) _buildProfileHeader(context, userData, api),
.animate() const SizedBox(height: Spacing.xl),
.fadeIn(duration: AnimationDuration.pageTransition) _buildAccountSection(context, ref),
.slideY( const SizedBox(height: Spacing.xl),
begin: 0.1, _buildSupportSection(context),
end: 0,
curve: AnimationCurves.pageTransition,
),
const SizedBox(height: Spacing.sectionGap),
_buildAccountSection(context, ref)
.animate()
.fadeIn(
delay: AnimationDelay.short,
duration: AnimationDuration.pageTransition,
)
.slideY(
begin: 0.08,
end: 0,
curve: AnimationCurves.pageTransition,
),
const SizedBox(height: Spacing.sectionGap),
_buildSupportSection(context)
.animate()
.fadeIn(
delay: AnimationDelay.medium,
duration: AnimationDuration.pageTransition,
)
.slideY(
begin: 0.08,
end: 0,
curve: AnimationCurves.pageTransition,
),
], ],
), ),
); );
@@ -318,25 +291,14 @@ class ProfilePage extends ConsumerWidget {
final accent = theme.buttonPrimary; final accent = theme.buttonPrimary;
return Container( return Container(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.all(Spacing.md),
horizontal: Spacing.md,
vertical: Spacing.sm,
),
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: LinearGradient( color: accent.withValues(alpha: 0.08),
begin: Alignment.topLeft, borderRadius: BorderRadius.circular(AppBorderRadius.large),
end: Alignment.bottomRight,
colors: [
accent.withValues(alpha: 0.22),
accent.withValues(alpha: 0.06),
],
),
borderRadius: BorderRadius.circular(AppBorderRadius.extraLarge),
border: Border.all( border: Border.all(
color: accent.withValues(alpha: 0.18), color: accent.withValues(alpha: 0.15),
width: BorderWidth.thin, width: BorderWidth.thin,
), ),
boxShadow: ConduitShadows.medium(context),
), ),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@@ -344,16 +306,10 @@ class ProfilePage extends ConsumerWidget {
Row( Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Container( UserAvatar(
decoration: BoxDecoration( size: 56,
borderRadius: BorderRadius.circular(AppBorderRadius.avatar), imageUrl: avatarUrl,
boxShadow: ConduitShadows.high(context), fallbackText: initial,
),
child: UserAvatar(
size: IconSize.avatar,
imageUrl: avatarUrl,
fallbackText: initial,
),
), ),
const SizedBox(width: Spacing.md), const SizedBox(width: Spacing.md),
Expanded( Expanded(
@@ -362,55 +318,34 @@ class ProfilePage extends ConsumerWidget {
children: [ children: [
Text( Text(
displayName, displayName,
style: style: theme.headingMedium?.copyWith(
theme.headingMedium?.copyWith( color: theme.textPrimary,
color: theme.textPrimary, fontWeight: FontWeight.w600,
fontWeight: FontWeight.w700, ),
) ??
TextStyle(
color: theme.textPrimary,
fontWeight: FontWeight.w700,
fontSize: 22,
),
), ),
const SizedBox(height: Spacing.sm), const SizedBox(height: Spacing.xs),
Container( Row(
padding: const EdgeInsets.symmetric( children: [
horizontal: Spacing.sm, Icon(
vertical: Spacing.xs, UiUtils.platformIcon(
), ios: CupertinoIcons.envelope,
decoration: BoxDecoration( android: Icons.mail_outline,
color: theme.surfaceBackground.withValues(alpha: 0.75), ),
borderRadius: BorderRadius.circular( size: IconSize.small,
AppBorderRadius.round, color: theme.textSecondary,
), ),
), const SizedBox(width: Spacing.xs),
child: Row( Flexible(
mainAxisSize: MainAxisSize.min, child: Text(
children: [ email,
Icon( style: theme.bodySmall?.copyWith(
UiUtils.platformIcon( color: theme.textSecondary,
ios: CupertinoIcons.envelope,
android: Icons.mail_outline,
), ),
size: IconSize.small, overflow: TextOverflow.ellipsis,
color: theme.textSecondary, maxLines: 1,
), ),
const SizedBox(width: Spacing.xs), ),
Flexible( ],
child: Text(
email,
style:
theme.bodySmall?.copyWith(
color: theme.textSecondary,
) ??
TextStyle(color: theme.textSecondary),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
),
],
),
), ),
], ],
), ),
@@ -523,11 +458,11 @@ class ProfilePage extends ConsumerWidget {
Widget leading; Widget leading;
if (selectedModelExplicit) { if (selectedModelExplicit) {
leading = Container( leading = Container(
width: 48, width: 40,
height: 48, height: 40,
decoration: BoxDecoration( decoration: BoxDecoration(
color: theme.surfaceBackground.withValues(alpha: 0.85), color: theme.surfaceBackground.withValues(alpha: 0.85),
borderRadius: BorderRadius.circular(AppBorderRadius.medium), borderRadius: BorderRadius.circular(AppBorderRadius.small),
border: Border.all( border: Border.all(
color: theme.cardBorder, color: theme.cardBorder,
width: BorderWidth.thin, width: BorderWidth.thin,
@@ -535,7 +470,7 @@ class ProfilePage extends ConsumerWidget {
), ),
alignment: Alignment.center, alignment: Alignment.center,
child: ModelAvatar( child: ModelAvatar(
size: 32, size: 28,
imageUrl: modelIconUrl, imageUrl: modelIconUrl,
label: currentModel.name, label: currentModel.name,
), ),
@@ -617,18 +552,18 @@ class ProfilePage extends ConsumerWidget {
required Color color, required Color color,
}) { }) {
return Container( return Container(
width: 48, width: 40,
height: 48, height: 40,
decoration: BoxDecoration( decoration: BoxDecoration(
color: color.withValues(alpha: Alpha.highlight), color: color.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(AppBorderRadius.medium), borderRadius: BorderRadius.circular(AppBorderRadius.small),
border: Border.all( border: Border.all(
color: color.withValues(alpha: 0.2), color: color.withValues(alpha: 0.2),
width: BorderWidth.thin, width: BorderWidth.thin,
), ),
), ),
alignment: Alignment.center, alignment: Alignment.center,
child: Icon(icon, color: color, size: IconSize.large), child: Icon(icon, color: color, size: IconSize.medium),
); );
} }
@@ -795,10 +730,7 @@ class _ProfileSettingTile extends StatelessWidget {
: theme.textSecondary; : theme.textSecondary;
return ConduitCard( return ConduitCard(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.all(Spacing.md),
horizontal: Spacing.listItemPadding,
vertical: Spacing.md,
),
onTap: onTap, onTap: onTap,
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
@@ -811,28 +743,24 @@ class _ProfileSettingTile extends StatelessWidget {
children: [ children: [
Text( Text(
title, title,
style: style: theme.bodyMedium?.copyWith(
theme.bodyLarge?.copyWith( color: textColor,
color: textColor, fontWeight: FontWeight.w600,
fontWeight: FontWeight.w600, ),
) ??
TextStyle(color: textColor, fontWeight: FontWeight.w600),
), ),
const SizedBox(height: Spacing.textSpacing), const SizedBox(height: Spacing.xs),
Text( Text(
subtitle, subtitle,
style: style: theme.bodySmall?.copyWith(color: subtitleColor),
theme.bodySmall?.copyWith(color: subtitleColor) ??
TextStyle(color: subtitleColor),
), ),
], ],
), ),
), ),
if (trailing != null) ...[ if (trailing != null) ...[
const SizedBox(width: Spacing.md), const SizedBox(width: Spacing.sm),
trailing!, trailing!,
] else if (showChevron && onTap != null) ...[ ] else if (showChevron && onTap != null) ...[
const SizedBox(width: Spacing.md), const SizedBox(width: Spacing.sm),
Icon( Icon(
UiUtils.platformIcon( UiUtils.platformIcon(
ios: CupertinoIcons.chevron_right, ios: CupertinoIcons.chevron_right,
@@ -1331,6 +1259,6 @@ class _DefaultModelBottomSheetState
), ),
), ),
), ),
).animate().fadeIn(duration: AnimationDuration.microInteraction); );
} }
} }