app/lib/ui/nav/nav_ui.dart
xkeyC 03c941c970 feat: 42kit Nav
feat: Animation Optimization
2025-05-04 14:07:56 +08:00

204 lines
7.4 KiB
Dart

import 'dart:ui';
import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter/gestures.dart' show TapGestureRecognizer;
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:flutter_tilt/flutter_tilt.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:starcitizen_doctor/ui/nav/nav_state.dart';
import 'package:url_launcher/url_launcher_string.dart';
import 'package:starcitizen_doctor/widgets/widgets.dart';
class NavUI extends HookConsumerWidget {
const NavUI({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 12),
child: Column(
children: [
Expanded(
child: buildBody(context, ref),
),
SizedBox(height: 6),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text.rich(
TextSpan(children: [
TextSpan(text: "*对应链接指向的服务由第三方提供,我们不对其做任何担保,请用户自行判断使用风险 | "),
TextSpan(text: "网站导航数据由"),
TextSpan(
text: " 42kit ",
style: TextStyle(
color: Colors.white,
decoration: TextDecoration.underline,
),
recognizer: TapGestureRecognizer()
..onTap = () {
launchUrlString("https://42kit.citizenwiki.cn/nav");
},
),
TextSpan(text: "提供"),
]),
style: TextStyle(
fontSize: 13,
color: Colors.white.withValues(alpha: .6),
),
),
SizedBox(width: 12),
],
),
],
),
);
}
Widget buildBody(BuildContext context, WidgetRef ref) {
final data = ref.watch(navProvider);
if (data.errorInfo.isNotEmpty) {
return Center(
child: Text(
data.errorInfo,
style: TextStyle(color: Colors.red),
),
);
}
if (data.items == null) {
return const Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ProgressRing(),
SizedBox(height: 12),
Text("正在获取数据..."),
],
));
}
return MasonryGridView.count(
crossAxisCount: 3,
mainAxisSpacing: 12,
crossAxisSpacing: 12,
itemCount: data.items!.length,
padding: EdgeInsets.only(left: 12, right: 12, bottom: 12),
itemBuilder: (BuildContext context, int index) {
const itemHeight = 160.0;
final item = data.items![index];
final itemName = item.name;
final itemImage = item.image.url;
return GridItemAnimator(
index: index,
child: GestureDetector(
onTap: () {
launchUrlString(item.link);
},
child: Tilt(
shadowConfig: const ShadowConfig(maxIntensity: .3),
borderRadius: BorderRadius.circular(12),
clipBehavior: Clip.hardEdge,
child: SizedBox(
height: itemHeight,
width: double.infinity,
child: ClipRRect(
borderRadius: BorderRadius.circular(12),
clipBehavior: Clip.hardEdge,
child: Stack(
children: [
Center(
child: CacheNetImage(
height: itemHeight,
width: double.infinity,
url: itemImage,
fit: BoxFit.fitWidth,
),
),
Container(
decoration: BoxDecoration(
color: Colors.black.withValues(alpha: .55),
),
),
ClipRect(
clipBehavior: Clip.hardEdge,
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 15.0, sigmaY: 15.0),
blendMode: BlendMode.srcOver,
child: SizedBox(
width: double.infinity,
height: itemHeight,
),
),
),
Container(
decoration: BoxDecoration(),
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(12),
child: CacheNetImage(
url: itemImage,
height: 48,
width: 48,
fit: BoxFit.cover,
),
),
SizedBox(width: 12),
Flexible(
child: Text(
itemName,
style: TextStyle(
fontSize: 18,
),
),
),
],
),
SizedBox(height: 12),
Expanded(
child: Text(
item.abstract_,
maxLines: 3,
overflow: TextOverflow.ellipsis,
style: TextStyle(color: Colors.white.withValues(alpha: .75)),
),
),
Row(
children: [
for (var value in item.tags)
Container(
decoration: BoxDecoration(
color: Colors.blue.withValues(alpha: .6),
borderRadius: BorderRadius.circular(12)),
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 3),
margin: EdgeInsets.only(right: 6),
child: Text(
value.name,
style: TextStyle(
fontSize: 13,
color: Colors.white,
),
),
)
],
)
],
),
),
],
),
),
),
),
),
);
},
);
}
}