refactor: tweaks
This commit is contained in:
@@ -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(
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user