fix:导航栏交互和UI
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
|
||||
import '../../data/api/report_data_source.dart';
|
||||
import '../../data/content_providers.dart';
|
||||
@@ -90,9 +89,7 @@ class FeedPage extends HookConsumerWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: YantingSpacing.x3),
|
||||
const ShadSeparator.horizontal(),
|
||||
const SizedBox(height: YantingSpacing.x3),
|
||||
const SizedBox(height: YantingSpacing.cardGap),
|
||||
if (visible.isEmpty)
|
||||
const EmptyState(
|
||||
title: '暂无可推荐的研报解读',
|
||||
@@ -115,7 +112,7 @@ class FeedPage extends HookConsumerWidget {
|
||||
),
|
||||
onPlayTap: () => _playFromReport(onPlay, visible.first),
|
||||
),
|
||||
const SizedBox(height: YantingSpacing.x6),
|
||||
const SizedBox(height: YantingSpacing.sectionGap),
|
||||
const SectionTitle(title: '最新解读', icon: Icons.chevron_right),
|
||||
for (final report in visible.skip(1)) ...[
|
||||
ReportCardWidget(
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
|
||||
import '../../data/api/report_data_source.dart';
|
||||
import '../../data/content_providers.dart';
|
||||
@@ -43,9 +42,7 @@ class InstitutionsPage extends HookConsumerWidget {
|
||||
),
|
||||
children: [
|
||||
const PageHeader(title: '机构', subtitle: '可获取研报的机构'),
|
||||
const SizedBox(height: YantingSpacing.x3),
|
||||
const ShadSeparator.horizontal(),
|
||||
const SizedBox(height: YantingSpacing.x3),
|
||||
const SizedBox(height: YantingSpacing.cardGap),
|
||||
for (final item in sorted) ...[
|
||||
InstitutionCard(
|
||||
institution: item,
|
||||
|
||||
@@ -52,8 +52,7 @@ class ListenPage extends HookConsumerWidget {
|
||||
onPlay: () => onPlay(current),
|
||||
),
|
||||
const SectionTitle(title: '全部音频', icon: AppIcons.arrowRight),
|
||||
const ShadSeparator.horizontal(),
|
||||
const SizedBox(height: YantingSpacing.x3),
|
||||
const SizedBox(height: YantingSpacing.cardGap),
|
||||
for (final item in items.skip(1)) ...[
|
||||
_AudioListCard(item: item, onPlay: () => onPlay(item)),
|
||||
const SizedBox(height: YantingSpacing.x3),
|
||||
@@ -115,12 +114,7 @@ class _ContinueListeningCard extends StatelessWidget {
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
ShadButton(
|
||||
onPressed: onPlay,
|
||||
width: 48,
|
||||
height: 48,
|
||||
child: const Icon(AppIcons.play, size: 18),
|
||||
),
|
||||
_PlayControlButton(onPressed: onPlay, size: 54, iconSize: 22),
|
||||
const SizedBox(width: 13),
|
||||
Expanded(
|
||||
child: Column(
|
||||
@@ -197,14 +191,41 @@ class _AudioListCard extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
ShadButton(
|
||||
onPressed: onPlay,
|
||||
width: 44,
|
||||
height: 44,
|
||||
child: const Icon(AppIcons.play, size: 16),
|
||||
),
|
||||
_PlayControlButton(onPressed: onPlay, size: 44, iconSize: 18),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _PlayControlButton extends StatelessWidget {
|
||||
const _PlayControlButton({
|
||||
required this.onPressed,
|
||||
required this.size,
|
||||
required this.iconSize,
|
||||
});
|
||||
|
||||
final VoidCallback onPressed;
|
||||
final double size;
|
||||
final double iconSize;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Material(
|
||||
color: YantingColors.primary,
|
||||
borderRadius: BorderRadius.circular(YantingRadius.pill),
|
||||
child: InkWell(
|
||||
onTap: onPressed,
|
||||
borderRadius: BorderRadius.circular(YantingRadius.pill),
|
||||
child: SizedBox.square(
|
||||
dimension: size,
|
||||
child: Icon(
|
||||
AppIcons.play,
|
||||
color: YantingColors.primaryForeground,
|
||||
size: iconSize,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +141,19 @@ class _MenuGroup extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return AppCard(
|
||||
padding: EdgeInsets.zero,
|
||||
child: Column(children: children),
|
||||
child: Column(
|
||||
children: [
|
||||
for (var index = 0; index < children.length; index++) ...[
|
||||
children[index],
|
||||
if (index != children.length - 1)
|
||||
const Divider(
|
||||
height: 1,
|
||||
thickness: 1,
|
||||
color: YantingColors.border,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,53 +99,66 @@ class ReportsPage extends HookConsumerWidget {
|
||||
),
|
||||
onChanged: (value) => query.value = value.trim(),
|
||||
),
|
||||
const SizedBox(height: YantingSpacing.x3),
|
||||
Wrap(
|
||||
spacing: YantingSpacing.x2,
|
||||
runSpacing: YantingSpacing.x2,
|
||||
const SizedBox(height: YantingSpacing.cardGap),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ShadButton.outline(
|
||||
onPressed: items.isEmpty
|
||||
? null
|
||||
: () => _openFilterSheet(
|
||||
context,
|
||||
items: items,
|
||||
topic: topic,
|
||||
Expanded(
|
||||
child: Wrap(
|
||||
spacing: YantingSpacing.x2,
|
||||
runSpacing: YantingSpacing.x2,
|
||||
children: [
|
||||
ShadButton.outline(
|
||||
onPressed: items.isEmpty
|
||||
? null
|
||||
: () => _openFilterSheet(
|
||||
context,
|
||||
items: items,
|
||||
topic: topic,
|
||||
),
|
||||
leading: const Icon(
|
||||
LucideIcons.slidersHorizontal,
|
||||
size: 16,
|
||||
),
|
||||
leading: const Icon(
|
||||
LucideIcons.slidersHorizontal,
|
||||
size: 16,
|
||||
child: const Text('筛选'),
|
||||
),
|
||||
ShadButton.outline(
|
||||
onPressed: () {},
|
||||
leading: const Icon(
|
||||
LucideIcons.arrowUpDown,
|
||||
size: 16,
|
||||
),
|
||||
child: const Text('最新'),
|
||||
),
|
||||
ShadBadge.secondary(
|
||||
onPressed: () => hasAudio.value = !currentHasAudio,
|
||||
backgroundColor: currentHasAudio
|
||||
? theme.colorScheme.foreground
|
||||
: theme.colorScheme.secondary,
|
||||
foregroundColor: currentHasAudio
|
||||
? theme.colorScheme.background
|
||||
: theme.colorScheme.secondaryForeground,
|
||||
hoverBackgroundColor: currentHasAudio
|
||||
? theme.colorScheme.foreground.withValues(
|
||||
alpha: 0.9,
|
||||
)
|
||||
: theme.colorScheme.border,
|
||||
child: const Text('音频'),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: const Text('筛选'),
|
||||
),
|
||||
ShadButton.outline(
|
||||
onPressed: () {},
|
||||
leading: const Icon(LucideIcons.arrowUpDown, size: 16),
|
||||
child: const Text('最新'),
|
||||
),
|
||||
ShadBadge.secondary(
|
||||
onPressed: () => hasAudio.value = !currentHasAudio,
|
||||
backgroundColor: currentHasAudio
|
||||
? theme.colorScheme.foreground
|
||||
: theme.colorScheme.secondary,
|
||||
foregroundColor: currentHasAudio
|
||||
? theme.colorScheme.background
|
||||
: theme.colorScheme.secondaryForeground,
|
||||
hoverBackgroundColor: currentHasAudio
|
||||
? theme.colorScheme.foreground.withValues(alpha: 0.9)
|
||||
: theme.colorScheme.border,
|
||||
child: const Text('音频'),
|
||||
const SizedBox(width: YantingSpacing.x2),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
child: Text(
|
||||
'共 ${filtered.length} 篇',
|
||||
style: YantingText.meta,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: Text('共 ${filtered.length} 篇', style: YantingText.meta),
|
||||
),
|
||||
const SizedBox(height: YantingSpacing.x3),
|
||||
const ShadSeparator.horizontal(),
|
||||
const SizedBox(height: YantingSpacing.x3),
|
||||
const SizedBox(height: YantingSpacing.cardGap),
|
||||
if (filtered.isEmpty)
|
||||
EmptyState(
|
||||
title: currentQuery.isNotEmpty ? '未找到相关研报' : '当前筛选下暂无研报',
|
||||
|
||||
@@ -31,8 +31,8 @@ class ReportCardWidget extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Wrap(
|
||||
spacing: WiseSpacing.x2,
|
||||
runSpacing: WiseSpacing.x2,
|
||||
spacing: hero ? WiseSpacing.x2 : 7,
|
||||
runSpacing: hero ? WiseSpacing.x2 : 7,
|
||||
children: [
|
||||
AppBadge(text: report.interpretationLabel, kind: BadgeKind.brand),
|
||||
if (report.hasAudio)
|
||||
@@ -46,27 +46,32 @@ class ReportCardWidget extends StatelessWidget {
|
||||
for (final topic in report.topics.take(3)) AppBadge(text: topic),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: WiseSpacing.x3),
|
||||
SizedBox(height: hero ? WiseSpacing.x3 : 10),
|
||||
Text(
|
||||
report.titleCn,
|
||||
maxLines: hero ? 3 : 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: hero
|
||||
? YantingText.sectionTitle.copyWith(fontSize: 21, height: 1.4)
|
||||
: YantingText.cardTitle,
|
||||
: YantingText.listTitle.copyWith(
|
||||
fontSize: 17.5,
|
||||
height: 1.38,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
if (report.oneLiner.isNotEmpty) ...[
|
||||
const SizedBox(height: WiseSpacing.x2),
|
||||
SizedBox(height: hero ? WiseSpacing.x2 : 7),
|
||||
Text(
|
||||
report.oneLiner,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: YantingText.body.copyWith(
|
||||
color: YantingColors.mutedForeground,
|
||||
fontSize: hero ? null : 14,
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: WiseSpacing.x3),
|
||||
SizedBox(height: hero ? WiseSpacing.x3 : 10),
|
||||
Wrap(
|
||||
crossAxisAlignment: WrapCrossAlignment.center,
|
||||
spacing: 8,
|
||||
@@ -96,6 +101,7 @@ class ReportCardWidget extends StatelessWidget {
|
||||
label: '听研报',
|
||||
icon: AppIcons.play,
|
||||
kind: hero ? AppButtonKind.primary : AppButtonKind.accent,
|
||||
compact: !hero,
|
||||
onPressed: onPlayTap,
|
||||
),
|
||||
],
|
||||
@@ -103,7 +109,11 @@ class ReportCardWidget extends StatelessWidget {
|
||||
);
|
||||
return hero
|
||||
? HeroReportCard(onTap: onTap, child: child)
|
||||
: AppCard(onTap: onTap, child: child);
|
||||
: AppCard(
|
||||
onTap: onTap,
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,20 +9,40 @@ import '../theme/yanting_text.dart';
|
||||
import '../widgets/bottom_tab_bar.dart';
|
||||
import '../widgets/mini_player.dart';
|
||||
|
||||
class ShellPage extends ConsumerWidget {
|
||||
class ShellPage extends ConsumerStatefulWidget {
|
||||
const ShellPage({required this.child, required this.currentPath, super.key});
|
||||
|
||||
final Widget child;
|
||||
final String currentPath;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
ConsumerState<ShellPage> createState() => _ShellPageState();
|
||||
}
|
||||
|
||||
class _ShellPageState extends ConsumerState<ShellPage> {
|
||||
static const double _compactHeaderThreshold = 34;
|
||||
|
||||
bool _showCompactHeader = false;
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant ShellPage oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (oldWidget.currentPath != widget.currentPath && _showCompactHeader) {
|
||||
_showCompactHeader = false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = ShadTheme.of(context);
|
||||
final player = ref.watch(audioPlayerControllerProvider);
|
||||
final controller = ref.read(audioPlayerControllerProvider.notifier);
|
||||
final canPop = GoRouter.of(context).canPop();
|
||||
final selectedIndex = _tabs.indexWhere((tab) => tab.path == currentPath);
|
||||
final selectedIndex = _tabs.indexWhere(
|
||||
(tab) => tab.path == widget.currentPath,
|
||||
);
|
||||
final safeIndex = selectedIndex < 0 ? 0 : selectedIndex;
|
||||
final header = _headerForPath(widget.currentPath);
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: theme.colorScheme.background,
|
||||
@@ -30,30 +50,45 @@ class ShellPage extends ConsumerWidget {
|
||||
backgroundColor: theme.colorScheme.background,
|
||||
surfaceTintColor: Colors.transparent,
|
||||
elevation: 0,
|
||||
scrolledUnderElevation: 0,
|
||||
centerTitle: true,
|
||||
leading: canPop
|
||||
? ShadIconButton.ghost(
|
||||
onPressed: () => context.pop(),
|
||||
icon: const Icon(LucideIcons.chevronLeft, size: 18),
|
||||
)
|
||||
: null,
|
||||
title: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('研听', style: YantingText.listTitle),
|
||||
Text('全球机构研报中文解读', style: YantingText.meta.copyWith(fontSize: 12)),
|
||||
],
|
||||
),
|
||||
bottom: PreferredSize(
|
||||
preferredSize: const Size.fromHeight(1),
|
||||
child: ColoredBox(
|
||||
color: theme.colorScheme.border,
|
||||
child: const SizedBox(height: 1, width: double.infinity),
|
||||
title: AnimatedOpacity(
|
||||
opacity: _showCompactHeader ? 1 : 0,
|
||||
duration: const Duration(milliseconds: 160),
|
||||
curve: Curves.easeOut,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
header.title,
|
||||
textAlign: TextAlign.center,
|
||||
style: YantingText.listTitle,
|
||||
),
|
||||
if (header.subtitle.isNotEmpty)
|
||||
Text(
|
||||
header.subtitle,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
textAlign: TextAlign.center,
|
||||
style: YantingText.meta.copyWith(fontSize: 12),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
body: ColoredBox(
|
||||
color: theme.colorScheme.background,
|
||||
child: Stack(children: [Positioned.fill(child: child)]),
|
||||
child: NotificationListener<ScrollNotification>(
|
||||
onNotification: _handleScrollNotification,
|
||||
child: Stack(children: [Positioned.fill(child: widget.child)]),
|
||||
),
|
||||
),
|
||||
bottomNavigationBar: SafeArea(
|
||||
top: false,
|
||||
@@ -71,6 +106,34 @@ class ShellPage extends ConsumerWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
bool _handleScrollNotification(ScrollNotification notification) {
|
||||
if (notification.metrics.axis != Axis.vertical) {
|
||||
return false;
|
||||
}
|
||||
final next = notification.metrics.pixels > _compactHeaderThreshold;
|
||||
if (next != _showCompactHeader && mounted) {
|
||||
setState(() => _showCompactHeader = next);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
_ShellHeader _headerForPath(String path) {
|
||||
return switch (path) {
|
||||
AppRoutes.reports => const _ShellHeader('研报', '全部已发布研报解读'),
|
||||
AppRoutes.institutions => const _ShellHeader('机构', '可获取研报的机构'),
|
||||
AppRoutes.listen => const _ShellHeader('听单', '已转音频的研报解读'),
|
||||
AppRoutes.profile => const _ShellHeader('我的', ''),
|
||||
_ => const _ShellHeader('研听', '全球机构研报中文解读'),
|
||||
};
|
||||
}
|
||||
|
||||
class _ShellHeader {
|
||||
const _ShellHeader(this.title, this.subtitle);
|
||||
|
||||
final String title;
|
||||
final String subtitle;
|
||||
}
|
||||
|
||||
class _TabItem {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
|
||||
import '../theme/yanting_text.dart';
|
||||
import '../theme/yanting_tokens.dart';
|
||||
|
||||
class AppButton extends StatelessWidget {
|
||||
@@ -10,6 +11,7 @@ class AppButton extends StatelessWidget {
|
||||
this.icon,
|
||||
this.kind = AppButtonKind.primary,
|
||||
this.expand = false,
|
||||
this.compact = false,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@@ -18,45 +20,49 @@ class AppButton extends StatelessWidget {
|
||||
final IconData? icon;
|
||||
final AppButtonKind kind;
|
||||
final bool expand;
|
||||
final bool compact;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final leading = icon == null ? null : Icon(icon, size: 16);
|
||||
final width = expand ? double.infinity : null;
|
||||
final child = Text(label);
|
||||
|
||||
return switch (kind) {
|
||||
AppButtonKind.primary => ShadButton(
|
||||
width: width,
|
||||
onPressed: onPressed,
|
||||
leading: leading,
|
||||
child: child,
|
||||
),
|
||||
AppButtonKind.dark => ShadButton(
|
||||
width: width,
|
||||
onPressed: onPressed,
|
||||
leading: leading,
|
||||
backgroundColor: YantingColors.foreground,
|
||||
foregroundColor: YantingColors.background,
|
||||
hoverBackgroundColor: YantingColors.foreground.withValues(alpha: 0.9),
|
||||
child: child,
|
||||
),
|
||||
AppButtonKind.accent => ShadButton.secondary(
|
||||
width: width,
|
||||
onPressed: onPressed,
|
||||
leading: leading,
|
||||
backgroundColor: YantingColors.brandSoft,
|
||||
foregroundColor: YantingColors.primaryForeground,
|
||||
hoverBackgroundColor: YantingColors.brandSoftBorder,
|
||||
child: child,
|
||||
),
|
||||
AppButtonKind.ghost => ShadButton.outline(
|
||||
width: width,
|
||||
onPressed: onPressed,
|
||||
leading: leading,
|
||||
child: child,
|
||||
),
|
||||
final variant = switch (kind) {
|
||||
AppButtonKind.primary => ShadButtonVariant.primary,
|
||||
AppButtonKind.dark => ShadButtonVariant.primary,
|
||||
AppButtonKind.accent => ShadButtonVariant.secondary,
|
||||
AppButtonKind.ghost => ShadButtonVariant.outline,
|
||||
};
|
||||
final colors = switch (kind) {
|
||||
AppButtonKind.primary => (null, null, null),
|
||||
AppButtonKind.dark => (
|
||||
YantingColors.foreground,
|
||||
YantingColors.background,
|
||||
YantingColors.foreground.withValues(alpha: 0.9),
|
||||
),
|
||||
AppButtonKind.accent => (
|
||||
YantingColors.brandSoft,
|
||||
YantingColors.primaryForeground,
|
||||
YantingColors.brandSoftBorder,
|
||||
),
|
||||
AppButtonKind.ghost => (null, null, null),
|
||||
};
|
||||
final button = ShadButton.raw(
|
||||
variant: variant,
|
||||
enabled: onPressed != null,
|
||||
onPressed: onPressed,
|
||||
width: expand ? double.infinity : null,
|
||||
height: compact ? 36 : 44,
|
||||
padding: EdgeInsets.symmetric(horizontal: compact ? 16 : 20),
|
||||
backgroundColor: colors.$1,
|
||||
foregroundColor: colors.$2,
|
||||
hoverBackgroundColor: colors.$3,
|
||||
leading: icon == null ? null : Icon(icon, size: compact ? 15 : 16),
|
||||
gap: compact ? 5 : 7,
|
||||
textStyle: (compact ? YantingText.badge : YantingText.body).copyWith(
|
||||
color: colors.$2,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
child: Text(label),
|
||||
);
|
||||
return expand ? SizedBox(width: double.infinity, child: button) : button;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+18
-17
@@ -1,5 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||
|
||||
import '../theme/yanting_tokens.dart';
|
||||
|
||||
@@ -21,29 +20,31 @@ class AppCard extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = ShadTheme.of(context);
|
||||
final radius = BorderRadius.circular(YantingRadius.xl);
|
||||
final content = ShadCard(
|
||||
padding: padding,
|
||||
backgroundColor: color,
|
||||
radius: radius,
|
||||
border: ShadBorder.all(color: borderColor),
|
||||
shadows: const [],
|
||||
child: child,
|
||||
final decoration = BoxDecoration(
|
||||
color: color,
|
||||
borderRadius: radius,
|
||||
border: Border.all(color: borderColor),
|
||||
);
|
||||
if (onTap == null) return content;
|
||||
if (onTap == null) {
|
||||
return DecoratedBox(
|
||||
decoration: decoration,
|
||||
child: Padding(padding: padding, child: child),
|
||||
);
|
||||
}
|
||||
|
||||
return Material(
|
||||
color: Colors.transparent,
|
||||
borderRadius: radius,
|
||||
child: InkWell(
|
||||
borderRadius: radius,
|
||||
splashColor: theme.colorScheme.mutedForeground.withValues(alpha: 0.08),
|
||||
highlightColor: theme.colorScheme.mutedForeground.withValues(
|
||||
alpha: 0.04,
|
||||
child: Ink(
|
||||
decoration: decoration,
|
||||
child: InkWell(
|
||||
borderRadius: radius,
|
||||
splashColor: YantingColors.mutedForeground.withValues(alpha: 0.08),
|
||||
highlightColor: YantingColors.mutedForeground.withValues(alpha: 0.04),
|
||||
onTap: onTap,
|
||||
child: Padding(padding: padding, child: child),
|
||||
),
|
||||
onTap: onTap,
|
||||
child: content,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -23,14 +23,14 @@ class InstitutionCard extends StatelessWidget {
|
||||
: institution.nameCn.characters.take(2).toString();
|
||||
return AppCard(
|
||||
onTap: onTap,
|
||||
padding: const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 14),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
InstitutionLogo(
|
||||
logoUrl: institution.logoUrl,
|
||||
initials: initials,
|
||||
size: 52,
|
||||
size: 48,
|
||||
),
|
||||
const SizedBox(width: 14),
|
||||
Expanded(
|
||||
@@ -54,10 +54,10 @@ class InstitutionCard extends StatelessWidget {
|
||||
style: YantingText.meta,
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 11),
|
||||
const SizedBox(height: 8),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
spacing: 7,
|
||||
runSpacing: 7,
|
||||
children: [
|
||||
if (institution.institutionType.isNotEmpty)
|
||||
AppBadge(
|
||||
@@ -71,14 +71,14 @@ class InstitutionCard extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const SizedBox(width: 10),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Text(
|
||||
'${institution.reportCount}',
|
||||
style: YantingText.sectionTitle.copyWith(
|
||||
fontSize: 21,
|
||||
fontSize: 20,
|
||||
fontFeatures: YantingTypographyFeatures.tabularNums,
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user