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:
@@ -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,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user