| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- import 'package:flutter/material.dart';
- import 'plugins.dart';
- /// 工具网格:可搜索的插件入口。
- ///
- /// 工具页面的实现全部在 lib/tools/ 下(从 mathtool2 搬过来的那批)。
- /// **计算一律交给 Symja**,走 lib/tools/tool_kit.dart 那套外壳;Dart 侧只有
- /// 绘图采样和排版。原来那批纯 Dart 的算法(rational / math_expressions)
- /// 已经全部撤掉 —— 同一个算式不该有 Dart 和 Symja 两份实现。
- class ToolsPage extends StatefulWidget {
- const ToolsPage({super.key});
- @override
- State<ToolsPage> createState() => _ToolsPageState();
- }
- class _ToolsPageState extends State<ToolsPage> {
- final _search = TextEditingController();
- String _q = '';
- static const _palette = <Color>[
- Color(0xFF5C6BC0),
- Color(0xFF26A69A),
- Color(0xFFEF5350),
- Color(0xFFAB47BC),
- Color(0xFF42A5F5),
- Color(0xFFFFA726),
- Color(0xFF66BB6A),
- Color(0xFF8D6E63),
- ];
- @override
- void dispose() {
- _search.dispose();
- super.dispose();
- }
- @override
- Widget build(BuildContext context) {
- final items = kTools.where((t) => t.matches(_q)).toList();
- // 这一页是唯一没有自己的 Scaffold/AppBar 的 tab(另外两个都有),
- // 所以得自己让开状态栏 —— 否则搜索框会顶到状态栏上,和时钟叠在一起。
- // bottom 不用让:下面紧挨着的就是 Shell 的 NavigationBar,它已经把
- // 底部安全区吃掉了。
- return SafeArea(
- bottom: false,
- child: Column(
- children: [
- Padding(
- padding: const EdgeInsets.fromLTRB(16, 12, 16, 8),
- child: TextField(
- controller: _search,
- decoration: InputDecoration(
- isDense: true,
- hintText: '搜索工具(支持拼音首字母)',
- prefixIcon: const Icon(Icons.search),
- suffixIcon: _q.isEmpty
- ? null
- : IconButton(
- icon: const Icon(Icons.clear),
- onPressed: () {
- _search.clear();
- setState(() => _q = '');
- },
- ),
- border: const OutlineInputBorder(),
- ),
- onChanged: (v) => setState(() => _q = v),
- ),
- ),
- Expanded(
- child: items.isEmpty
- ? const Center(child: Text('没有匹配的工具'))
- : GridView.builder(
- padding: const EdgeInsets.fromLTRB(16, 8, 16, 16),
- gridDelegate:
- const SliverGridDelegateWithFixedCrossAxisCount(
- crossAxisCount: 2,
- mainAxisSpacing: 12,
- crossAxisSpacing: 12,
- childAspectRatio: 1.5,
- ),
- itemCount: items.length,
- itemBuilder: (_, i) {
- final t = items[i];
- final color =
- _palette[kTools.indexOf(t) % _palette.length];
- return _ToolCard(
- plugin: t,
- color: color,
- onTap: () => Navigator.of(context).push(
- MaterialPageRoute<void>(
- builder: (_) => t.build(),
- settings: RouteSettings(name: t.name),
- ),
- ),
- );
- },
- ),
- ),
- ],
- ),
- );
- }
- }
- class _ToolCard extends StatelessWidget {
- const _ToolCard({
- required this.plugin,
- required this.color,
- required this.onTap,
- });
- final ToolPlugin plugin;
- final Color color;
- final VoidCallback onTap;
- @override
- Widget build(BuildContext context) {
- return Material(
- color: Colors.transparent,
- child: InkWell(
- onTap: onTap,
- borderRadius: BorderRadius.circular(16),
- child: Ink(
- decoration: BoxDecoration(
- borderRadius: BorderRadius.circular(16),
- gradient: LinearGradient(
- begin: Alignment.topLeft,
- end: Alignment.bottomRight,
- colors: [color, Color.lerp(color, Colors.black, 0.22)!],
- ),
- ),
- padding: const EdgeInsets.all(14),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- Icon(plugin.icon, color: Colors.white, size: 26),
- Text(
- plugin.name,
- style: const TextStyle(
- color: Colors.white,
- fontSize: 15,
- fontWeight: FontWeight.w600,
- ),
- ),
- ],
- ),
- ),
- ),
- );
- }
- }
|