refactor: tweaks

This commit is contained in:
cogwheel0
2025-09-20 18:09:22 +05:30
parent 1fc1cf9739
commit 093e8f3c0d
3 changed files with 177 additions and 327 deletions

View File

@@ -934,19 +934,32 @@ class _ChatPageState extends ConsumerState<ChatPage> {
final conversationTitle = ref.watch( final conversationTitle = ref.watch(
activeConversationProvider.select((conv) => conv?.title), activeConversationProvider.select((conv) => conv?.title),
); );
final displayConversationTitle = (() { final trimmedConversationTitle = conversationTitle?.trim();
final trimmed = conversationTitle?.trim(); final displayConversationTitle =
if (trimmed != null && trimmed.isNotEmpty) { (trimmedConversationTitle != null &&
return trimmed; trimmedConversationTitle.isNotEmpty)
} ? trimmedConversationTitle
return l10n.newChat; : null;
})();
final formattedModelName = selectedModel != null final formattedModelName = selectedModel != null
? _formatModelDisplayName( ? _formatModelDisplayName(
selectedModel.name, selectedModel.name,
omitProvider: omitProviderInModelName, omitProvider: omitProviderInModelName,
) )
: null; : null;
final modelLabel = formattedModelName ?? l10n.chooseModel;
final hasConversationTitle = displayConversationTitle != null;
final TextStyle modelTextStyle = hasConversationTitle
? AppTypography.small.copyWith(
color: context.conduitTheme.textSecondary,
fontWeight: FontWeight.w600,
height: 1.2,
)
: AppTypography.headlineSmallStyle.copyWith(
color: context.conduitTheme.textPrimary,
fontWeight: FontWeight.w600,
fontSize: 18,
height: 1.3,
);
// Keyboard visibility // Keyboard visibility
final keyboardVisible = MediaQuery.of(context).viewInsets.bottom > 0; final keyboardVisible = MediaQuery.of(context).viewInsets.bottom > 0;
@@ -1060,16 +1073,16 @@ class _ChatPageState extends ConsumerState<ChatPage> {
onPressed: _clearSelection, onPressed: _clearSelection,
) )
: Builder( : Builder(
builder: (ctx) => GestureDetector( builder: (ctx) => Padding(
onTap: () { padding: const EdgeInsets.only(
// Open left drawer instead of bottom sheet left: Spacing.inputPadding,
Scaffold.of(ctx).openDrawer(); ),
}, child: IconButton(
child: Padding( onPressed: () {
padding: const EdgeInsets.only( // Open left drawer instead of bottom sheet
left: Spacing.inputPadding, Scaffold.of(ctx).openDrawer();
), },
child: Icon( icon: Icon(
Platform.isIOS Platform.isIOS
? CupertinoIcons.line_horizontal_3 ? CupertinoIcons.line_horizontal_3
: Icons.menu, : Icons.menu,
@@ -1087,155 +1100,6 @@ class _ChatPageState extends ConsumerState<ChatPage> {
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
), ),
) )
: selectedModel != null
? GestureDetector(
onTap: () {
final modelsAsync = ref.read(modelsProvider);
modelsAsync.whenData(
(models) => _showModelDropdown(context, ref, models),
);
},
onLongPress: () {
final conversation = ref.read(activeConversationProvider);
if (conversation == null) return;
showConversationContextMenu(
context: context,
ref: ref,
conversation: conversation,
);
},
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
MiddleEllipsisText(
displayConversationTitle,
style: AppTypography.headlineSmallStyle.copyWith(
color: context.conduitTheme.textPrimary,
fontWeight: FontWeight.w600,
fontSize: 18,
height: 1.3,
),
textAlign: TextAlign.center,
semanticsLabel: displayConversationTitle,
),
const SizedBox(height: Spacing.xs),
Transform.translate(
offset: const Offset(0, 0),
child: SizedBox(
height: 24,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
Opacity(
opacity: 0.0,
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: Spacing.xs,
vertical: Spacing.xxs,
),
decoration: BoxDecoration(
color: context
.conduitTheme
.surfaceBackground
.withValues(alpha: 0.3),
borderRadius: BorderRadius.circular(
AppBorderRadius.badge,
),
border: Border.all(
color:
context.conduitTheme.dividerColor,
width: BorderWidth.thin,
),
),
child: Icon(
Platform.isIOS
? CupertinoIcons.chevron_down
: Icons.keyboard_arrow_down,
color: context.conduitTheme.iconSecondary,
size: IconSize.small,
),
),
),
const SizedBox(width: Spacing.xs),
Flexible(
child: MiddleEllipsisText(
formattedModelName!,
style: AppTypography.small.copyWith(
color: context.conduitTheme.textSecondary,
fontWeight: FontWeight.w600,
height: 1.2,
),
textAlign: TextAlign.center,
semanticsLabel: formattedModelName,
),
),
const SizedBox(width: Spacing.xs),
Container(
padding: const EdgeInsets.symmetric(
horizontal: Spacing.xs,
vertical: Spacing.xxs,
),
decoration: BoxDecoration(
color: context
.conduitTheme
.surfaceBackground
.withValues(alpha: 0.3),
borderRadius: BorderRadius.circular(
AppBorderRadius.badge,
),
border: Border.all(
color: context.conduitTheme.dividerColor,
width: BorderWidth.thin,
),
),
child: Icon(
Platform.isIOS
? CupertinoIcons.chevron_down
: Icons.keyboard_arrow_down,
color: context.conduitTheme.iconSecondary,
size: IconSize.small,
),
),
],
),
),
),
if (isReviewerMode)
Padding(
padding: const EdgeInsets.only(top: 2.0),
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: Spacing.sm,
vertical: 1.0,
),
decoration: BoxDecoration(
color: context.conduitTheme.success.withValues(
alpha: 0.1,
),
borderRadius: BorderRadius.circular(
AppBorderRadius.badge,
),
border: Border.all(
color: context.conduitTheme.success
.withValues(alpha: 0.3),
width: BorderWidth.thin,
),
),
child: Text(
'REVIEWER MODE',
style: AppTypography.captionStyle.copyWith(
color: context.conduitTheme.success,
fontWeight: FontWeight.w600,
fontSize: 9,
),
),
),
),
],
),
)
: GestureDetector( : GestureDetector(
onTap: () { onTap: () {
final modelsAsync = ref.read(modelsProvider); final modelsAsync = ref.read(modelsProvider);
@@ -1256,23 +1120,40 @@ class _ChatPageState extends ConsumerState<ChatPage> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
MiddleEllipsisText( AnimatedSwitcher(
displayConversationTitle, duration: const Duration(milliseconds: 250),
style: AppTypography.headlineSmallStyle.copyWith( switchInCurve: Curves.easeOutCubic,
color: context.conduitTheme.textPrimary, switchOutCurve: Curves.easeInCubic,
fontWeight: FontWeight.w600, child: displayConversationTitle != null
fontSize: 18, ? Column(
height: 1.3, key: const ValueKey<bool>(true),
), mainAxisSize: MainAxisSize.min,
textAlign: TextAlign.center, children: [
semanticsLabel: displayConversationTitle, MiddleEllipsisText(
displayConversationTitle,
style: AppTypography.headlineSmallStyle
.copyWith(
color: context
.conduitTheme
.textPrimary,
fontWeight: FontWeight.w600,
fontSize: 18,
height: 1.3,
),
textAlign: TextAlign.center,
semanticsLabel: displayConversationTitle,
),
const SizedBox(height: Spacing.xs),
],
)
: const SizedBox.shrink(
key: ValueKey<bool>(false),
),
), ),
const SizedBox(height: Spacing.xs),
Transform.translate( Transform.translate(
offset: const Offset(0, 0), offset: const Offset(0, 0),
child: SizedBox( child: () {
height: 24, final row = Row(
child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
@@ -1309,14 +1190,10 @@ class _ChatPageState extends ConsumerState<ChatPage> {
const SizedBox(width: Spacing.xs), const SizedBox(width: Spacing.xs),
Flexible( Flexible(
child: MiddleEllipsisText( child: MiddleEllipsisText(
l10n.chooseModel, modelLabel,
style: AppTypography.small.copyWith( style: modelTextStyle,
color: context.conduitTheme.textSecondary,
fontWeight: FontWeight.w600,
height: 1.2,
),
textAlign: TextAlign.center, textAlign: TextAlign.center,
semanticsLabel: l10n.chooseModel, semanticsLabel: modelLabel,
), ),
), ),
const SizedBox(width: Spacing.xs), const SizedBox(width: Spacing.xs),
@@ -1347,8 +1224,11 @@ class _ChatPageState extends ConsumerState<ChatPage> {
), ),
), ),
], ],
), );
), return hasConversationTitle
? SizedBox(height: 24, child: row)
: row;
}(),
), ),
if (isReviewerMode) if (isReviewerMode)
Padding( Padding(

View File

@@ -333,6 +333,9 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
final Brightness brightness = Theme.of(context).brightness; final Brightness brightness = Theme.of(context).brightness;
final bool isActive = _focusNode.hasFocus || _hasText; final bool isActive = _focusNode.hasFocus || _hasText;
final Color composerSurface = context.conduitTheme.inputBackground; final Color composerSurface = context.conduitTheme.inputBackground;
final Color composerBackground = brightness == Brightness.dark
? composerSurface.withValues(alpha: 0.78)
: context.conduitTheme.surfaceContainerHighest;
final Color placeholderBase = context.conduitTheme.inputPlaceholder; final Color placeholderBase = context.conduitTheme.inputPlaceholder;
final Color placeholderFocused = context.conduitTheme.inputText.withValues( final Color placeholderFocused = context.conduitTheme.inputText.withValues(
alpha: 0.64, alpha: 0.64,
@@ -428,9 +431,7 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
duration: const Duration(milliseconds: 180), duration: const Duration(milliseconds: 180),
curve: Curves.easeOutCubic, curve: Curves.easeOutCubic,
decoration: BoxDecoration( decoration: BoxDecoration(
color: brightness == Brightness.dark color: composerBackground,
? composerSurface.withValues(alpha: 0.78)
: composerSurface,
borderRadius: BorderRadius.circular(_composerRadius), borderRadius: BorderRadius.circular(_composerRadius),
border: Border.all(color: outlineColor, width: BorderWidth.thin), border: Border.all(color: outlineColor, width: BorderWidth.thin),
boxShadow: [ boxShadow: [
@@ -462,9 +463,19 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.all(Spacing.sm), padding: const EdgeInsets.fromLTRB(
Spacing.sm,
Spacing.xs,
Spacing.sm,
Spacing.xs,
),
child: Container( child: Container(
padding: const EdgeInsets.all(Spacing.sm), padding: const EdgeInsets.fromLTRB(
Spacing.sm,
Spacing.xs,
Spacing.sm,
Spacing.xs,
),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.transparent, color: Colors.transparent,
borderRadius: BorderRadius.circular(_composerRadius), borderRadius: BorderRadius.circular(_composerRadius),
@@ -555,6 +566,13 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
factor, factor,
)!; )!;
final FontWeight recordingWeight =
_isRecording
? FontWeight.w500
: FontWeight.w400;
final TextStyle baseChatStyle =
AppTypography.chatMessageStyle;
return TextField( return TextField(
controller: _controller, controller: _controller,
focusNode: _focusNode, focusNode: _focusNode,
@@ -576,27 +594,20 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
), ),
keyboardAppearance: brightness, keyboardAppearance: brightness,
cursorColor: animatedTextColor, cursorColor: animatedTextColor,
style: AppTypography.bodyLargeStyle style: baseChatStyle.copyWith(
.copyWith( color: animatedTextColor,
color: animatedTextColor, fontStyle: _isRecording
fontStyle: _isRecording ? FontStyle.italic
? FontStyle.italic : FontStyle.normal,
: FontStyle.normal, fontWeight: recordingWeight,
fontWeight: _isRecording ),
? FontWeight.w500
: FontWeight.w400,
),
decoration: InputDecoration( decoration: InputDecoration(
hintText: AppLocalizations.of( hintText: AppLocalizations.of(
context, context,
)!.messageHintText, )!.messageHintText,
hintStyle: TextStyle( hintStyle: baseChatStyle.copyWith(
color: animatedPlaceholder, color: animatedPlaceholder,
fontSize: fontWeight: recordingWeight,
AppTypography.bodyLarge,
fontWeight: _isRecording
? FontWeight.w500
: FontWeight.w400,
fontStyle: _isRecording fontStyle: _isRecording
? FontStyle.italic ? FontStyle.italic
: FontStyle.normal, : FontStyle.normal,
@@ -610,7 +621,7 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
contentPadding: contentPadding:
const EdgeInsets.symmetric( const EdgeInsets.symmetric(
horizontal: Spacing.sm, horizontal: Spacing.sm,
vertical: Spacing.sm, vertical: Spacing.xs,
), ),
isDense: true, isDense: true,
alignLabelWithHint: true, alignLabelWithHint: true,
@@ -647,6 +658,9 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
children: [ children: [
_buildOverflowButton( _buildOverflowButton(
tooltip: AppLocalizations.of(context)!.more, tooltip: AppLocalizations.of(context)!.more,
webSearchActive: webSearchEnabled,
imageGenerationActive: imageGenEnabled,
toolsActive: selectedToolIds.isNotEmpty,
), ),
const SizedBox(width: Spacing.xs), const SizedBox(width: Spacing.xs),
Expanded( Expanded(
@@ -705,12 +719,7 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
return Container( return Container(
color: Colors.transparent, color: Colors.transparent,
padding: const EdgeInsets.only( padding: EdgeInsets.zero,
left: 0,
right: 0,
top: Spacing.xs,
bottom: 0,
),
child: Column(mainAxisSize: MainAxisSize.min, children: [shell]), child: Column(mainAxisSize: MainAxisSize.min, children: [shell]),
); );
} }
@@ -778,14 +787,61 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
return result; return result;
} }
Widget _buildOverflowButton({required String tooltip}) { Widget _buildOverflowButton({
final IconData icon = Platform.isIOS required String tooltip,
? CupertinoIcons.ellipsis required bool webSearchActive,
: Icons.more_horiz; required bool imageGenerationActive,
return _buildRoundButton( required bool toolsActive,
icon: icon, }) {
onTap: widget.enabled && !_isRecording ? _showOverflowSheet : null, final bool enabled = widget.enabled && !_isRecording;
tooltip: tooltip,
IconData icon;
Color? activeColor;
if (webSearchActive) {
icon = Platform.isIOS ? CupertinoIcons.search : Icons.search;
activeColor = context.conduitTheme.buttonPrimary;
} else if (imageGenerationActive) {
icon = Platform.isIOS ? CupertinoIcons.photo : Icons.image;
activeColor = context.conduitTheme.buttonPrimary;
} else if (toolsActive) {
icon = Platform.isIOS ? CupertinoIcons.wrench : Icons.build;
activeColor = context.conduitTheme.buttonPrimary;
} else {
icon = Platform.isIOS ? CupertinoIcons.add : Icons.add;
activeColor = null;
}
const double iconSize = IconSize.large;
final Color iconColor = !enabled
? context.conduitTheme.textPrimary.withValues(alpha: Alpha.disabled)
: (activeColor ??
context.conduitTheme.textPrimary.withValues(alpha: Alpha.strong));
return Tooltip(
message: tooltip,
child: Opacity(
opacity: enabled ? 1.0 : Alpha.disabled,
child: SizedBox(
width: TouchTarget.minimum,
height: TouchTarget.minimum,
child: Material(
color: Colors.transparent,
child: InkWell(
borderRadius: BorderRadius.circular(AppBorderRadius.round),
onTap: enabled
? () {
HapticFeedback.selectionClick();
_showOverflowSheet();
}
: null,
child: Center(
child: Icon(icon, size: iconSize, color: iconColor),
),
),
),
),
),
); );
} }
@@ -910,68 +966,6 @@ class _ModernChatInputState extends ConsumerState<ModernChatInput>
); );
} }
Widget _buildRoundButton({
required IconData icon,
VoidCallback? onTap,
String? tooltip,
bool isActive = false,
}) {
const double buttonSize = TouchTarget.minimum;
final VoidCallback? callback = onTap;
final bool enabled = callback != null;
final Color borderColor = isActive
? context.conduitTheme.buttonPrimary
: context.conduitTheme.cardBorder.withValues(
alpha: enabled ? Alpha.medium : Alpha.disabled,
);
final Color fillColor = isActive
? context.conduitTheme.buttonPrimary.withValues(alpha: 0.18)
: context.conduitTheme.cardBackground;
final Color iconColor = enabled
? (isActive
? context.conduitTheme.buttonPrimaryText
: context.conduitTheme.textPrimary.withValues(
alpha: Alpha.strong,
))
: context.conduitTheme.textPrimary.withValues(alpha: Alpha.disabled);
return Tooltip(
message: tooltip ?? '',
child: Opacity(
opacity: enabled ? 1.0 : Alpha.disabled,
child: IgnorePointer(
ignoring: !enabled,
child: Material(
color: Colors.transparent,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppBorderRadius.round),
side: BorderSide(color: borderColor, width: BorderWidth.thin),
),
child: InkWell(
borderRadius: BorderRadius.circular(AppBorderRadius.round),
onTap: onTap == null
? null
: () {
HapticFeedback.selectionClick();
onTap();
},
child: Container(
width: buttonSize,
height: buttonSize,
decoration: BoxDecoration(
color: fillColor,
borderRadius: BorderRadius.circular(AppBorderRadius.round),
boxShadow: ConduitShadows.button,
),
child: Icon(icon, size: IconSize.medium, color: iconColor),
),
),
),
),
),
);
}
Widget _buildPillButton({ Widget _buildPillButton({
required IconData icon, required IconData icon,
required String label, required String label,

View File

@@ -146,28 +146,7 @@ class _ChatsDrawerState extends ConsumerState<ChatsDrawer> {
Spacing.md, Spacing.md,
Spacing.sm, Spacing.sm,
), ),
child: Row( child: Row(children: [Expanded(child: _buildSearchField(context))]),
children: [
Expanded(child: _buildSearchField(context)),
const SizedBox(width: Spacing.sm),
IconButton(
icon: Icon(
Platform.isIOS ? CupertinoIcons.create : Icons.add_comment,
color: theme.iconPrimary,
size: IconSize.lg,
),
onPressed: () {
chat.startNewChat(ref);
if (mounted) Navigator.of(context).maybePop();
},
tooltip: AppLocalizations.of(context)!.newChat,
constraints: const BoxConstraints(
minWidth: TouchTarget.comfortable,
minHeight: TouchTarget.comfortable,
),
),
],
),
), ),
Expanded(child: _buildConversationList(context)), Expanded(child: _buildConversationList(context)),
Divider(height: 1, color: theme.dividerColor), Divider(height: 1, color: theme.dividerColor),
@@ -1218,7 +1197,10 @@ class _ChatsDrawerState extends ConsumerState<ChatsDrawer> {
if (user != null) ...[ if (user != null) ...[
const SizedBox(height: Spacing.sm), const SizedBox(height: Spacing.sm),
Container( Container(
padding: const EdgeInsets.all(Spacing.sm), padding: const EdgeInsets.symmetric(
horizontal: Spacing.sm,
vertical: Spacing.xs,
),
decoration: BoxDecoration( decoration: BoxDecoration(
color: theme.surfaceContainer.withValues(alpha: 0.05), color: theme.surfaceContainer.withValues(alpha: 0.05),
borderRadius: BorderRadius.circular(AppBorderRadius.md), borderRadius: BorderRadius.circular(AppBorderRadius.md),
@@ -1231,8 +1213,8 @@ class _ChatsDrawerState extends ConsumerState<ChatsDrawer> {
child: Row( child: Row(
children: [ children: [
Container( Container(
width: IconSize.avatar, width: IconSize.xl,
height: IconSize.avatar, height: IconSize.xl,
decoration: BoxDecoration( decoration: BoxDecoration(
color: theme.buttonPrimary.withValues(alpha: 0.15), color: theme.buttonPrimary.withValues(alpha: 0.15),
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(
@@ -1252,7 +1234,7 @@ class _ChatsDrawerState extends ConsumerState<ChatsDrawer> {
), ),
), ),
), ),
const SizedBox(width: Spacing.sm), const SizedBox(width: Spacing.xs),
Expanded( Expanded(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@@ -1261,7 +1243,7 @@ class _ChatsDrawerState extends ConsumerState<ChatsDrawer> {
displayName, displayName,
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: AppTypography.standard.copyWith( style: AppTypography.bodySmallStyle.copyWith(
color: theme.textPrimary, color: theme.textPrimary,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
), ),
@@ -1314,14 +1296,13 @@ class _ConversationDragFeedback extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final borderColor = pinned final borderRadius = BorderRadius.circular(AppBorderRadius.navigation);
? theme.navigationSelected.withValues(alpha: 0.35) final borderColor = theme.surfaceContainerHighest.withValues(alpha: 0.40);
: theme.surfaceContainerHighest.withValues(alpha: 0.45);
return Material( return Material(
color: Colors.transparent, color: Colors.transparent,
elevation: Elevation.low, elevation: Elevation.low,
borderRadius: BorderRadius.zero, borderRadius: borderRadius,
child: Container( child: Container(
constraints: const BoxConstraints(minHeight: TouchTarget.listItem), constraints: const BoxConstraints(minHeight: TouchTarget.listItem),
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
@@ -1330,7 +1311,7 @@ class _ConversationDragFeedback extends StatelessWidget {
), ),
decoration: BoxDecoration( decoration: BoxDecoration(
color: theme.surfaceContainer, color: theme.surfaceContainer,
borderRadius: BorderRadius.zero, borderRadius: borderRadius,
border: Border.all(color: borderColor, width: BorderWidth.thin), border: Border.all(color: borderColor, width: BorderWidth.thin),
), ),
child: _ConversationTileContent( child: _ConversationTileContent(
@@ -1472,14 +1453,9 @@ class _ConversationTile extends StatelessWidget {
alpha: brightness == Brightness.dark ? 0.28 : 0.16, alpha: brightness == Brightness.dark ? 0.28 : 0.16,
) )
: theme.surfaceContainer; : theme.surfaceContainer;
final Color borderColor; final Color borderColor = selected
if (selected) { ? theme.buttonPrimary.withValues(alpha: 0.7)
borderColor = theme.buttonPrimary.withValues(alpha: 0.7); : theme.surfaceContainerHighest.withValues(alpha: 0.40);
} else if (pinned) {
borderColor = theme.buttonPrimary.withValues(alpha: 0.35);
} else {
borderColor = theme.surfaceContainerHighest.withValues(alpha: 0.40);
}
final List<BoxShadow> shadow = selected ? ConduitShadows.low : const []; final List<BoxShadow> shadow = selected ? ConduitShadows.low : const [];
Color? overlayForStates(Set<WidgetState> states) { Color? overlayForStates(Set<WidgetState> states) {