├── .gitignore
├── .metadata
├── .vscode
└── settings.json
├── CHANGELOG.md
├── LICENSE
├── README.md
├── analysis_options.yaml
├── example
└── main.dart
├── lib
├── ant_design_flutter.dart
└── src
│ ├── enum
│ ├── placement.dart
│ ├── size.dart
│ ├── status.dart
│ ├── theme.dart
│ └── trigger.dart
│ ├── style
│ ├── color.dart
│ └── icon.dart
│ └── widget
│ ├── affix.dart
│ ├── alert.dart
│ ├── anchor.dart
│ ├── app.dart
│ ├── auto_complete.dart
│ ├── avatar.dart
│ ├── badge.dart
│ ├── breadcrumb.dart
│ ├── button.dart
│ ├── calendar.dart
│ ├── card.dart
│ ├── carousel.dart
│ ├── cascader.dart
│ ├── checkbox.dart
│ ├── collapse.dart
│ ├── color_picker.dart
│ ├── config_provider.dart
│ ├── date_picker.dart
│ ├── descriptions.dart
│ ├── divider.dart
│ ├── drawer.dart
│ ├── dropdown.dart
│ ├── empty.dart
│ ├── flex.dart
│ ├── float_button.dart
│ ├── form.dart
│ ├── grid.dart
│ ├── icon.dart
│ ├── image.dart
│ ├── input.dart
│ ├── input_number.dart
│ ├── layout.dart
│ ├── list.dart
│ ├── mentions.dart
│ ├── menu.dart
│ ├── message.dart
│ ├── modal.dart
│ ├── nested_gesture_detector.dart
│ ├── notification.dart
│ ├── page_header.dart
│ ├── pagination.dart
│ ├── popconfirm.dart
│ ├── popover.dart
│ ├── progress.dart
│ ├── qr_code.dart
│ ├── radio.dart
│ ├── rate.dart
│ ├── result.dart
│ ├── scaffold.dart
│ ├── segmented.dart
│ ├── select.dart
│ ├── skeleton.dart
│ ├── slider.dart
│ ├── space.dart
│ ├── spin.dart
│ ├── statistic.dart
│ ├── steps.dart
│ ├── switch.dart
│ ├── table.dart
│ ├── tabs.dart
│ ├── tag.dart
│ ├── time_picker.dart
│ ├── tooltip.dart
│ ├── tour.dart
│ ├── transfer.dart
│ ├── tree.dart
│ ├── tree_select.dart
│ ├── typography.dart
│ ├── upload.dart
│ └── watermark.dart
├── pubspec.yaml
└── test
└── antdf_test.dart
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | # Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
25 | /pubspec.lock
26 | **/doc/api/
27 | .dart_tool/
28 | .packages
29 | build/
30 |
--------------------------------------------------------------------------------
/.metadata:
--------------------------------------------------------------------------------
1 | # This file tracks properties of this Flutter project.
2 | # Used by Flutter tool to assess capabilities and perform upgrades etc.
3 | #
4 | # This file should be version controlled and should not be manually edited.
5 |
6 | version:
7 | revision: 7e9793dee1b85a243edd0e06cb1658e98b077561
8 | channel: stable
9 |
10 | project_type: package
11 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "cSpell.words": ["cascader", "vsync"]
3 | }
4 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 0.0.1+5
2 |
3 | - Redesign color of button
4 |
5 | ## 0.0.1+4
6 |
7 | - Upgrade flutter_lints to 2.0
8 | - Some feature of Button widget
9 |
10 | ## 0.0.1+3
11 |
12 | - Hide raw MenuItem to avoid comflict since Flutter 3.0 brings PlatformMenuBar
13 | - Some feature of widgets
14 |
15 | ## 0.0.1+2
16 |
17 | - Remove 'Ant' prefix of some widgets and hide the same name raw widget to avoid comflict.
18 |
19 | ## 0.0.1+1
20 |
21 | - Update README.md.
22 |
23 | ## 0.0.1
24 |
25 | - Build some common widgets.
26 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT LICENSE
2 |
3 | Copyright (c) 2022 Cals Ranna, https://github.com/CalsRanna
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Ant Design Flutter
8 |
9 |
10 |
11 | A Flutter UI framework designed for web / pc application, contains some high quality widgets.
12 |
13 | Since antdf is designed for pc application at very first, so it wasn't recommand to use in mobile application even can be used.
14 |
15 |   
16 |
17 |
18 |
19 | [](https://doc.antdf.xyz)
20 |
21 | ## ✨ Features
22 |
23 | - 🌈 Enterprise-class UI designed for web / desktop applications.
24 | - 📦 A set of high-quality Flutter widgets out of the box.
25 | - 🛡 Written in pure Dart with null safety.
26 |
27 | ## 🖥 Environment Support
28 |
29 | - Working on Windows and Mac OS
30 |
31 | ## 📦 Install
32 |
33 | ```bash
34 | flutter pub add ant_design_flutter
35 | ```
36 |
37 | ## 🔨 Usage
38 |
39 | ```dart
40 | import 'package:ant_design_flutter/antdf.dart';
41 |
42 | void main() {
43 | runApp(const AntApp(
44 | home: Scaffold(
45 | body: Center(
46 | child: Button(
47 | type: ButtonType.primary,
48 | child: Text("Click Me"),
49 | ),
50 | )
51 | ),
52 | ));
53 | }
54 | ```
55 |
56 | ### Null Safety
57 |
58 | `antdf` is written in dart with null safety, check [Sound Null Safety](https://flutter.cn/posts/announcing-dart-2-12#%E5%81%A5%E5%85%A8%E7%9A%84%E7%A9%BA%E5%AE%89%E5%85%A8) to get started.
59 |
60 | ## 🔗 Links
61 |
62 | - [Home page](https://doc.antdf.xyz)
63 | - [Widgets Overview](https://doc.antdf.xyz/#/overview)
64 |
65 | ## ⌨️ Development
66 |
67 | Use Gitpod, a free online dev environment for GitHub.
68 |
69 | [](https://gitpod.io/#https://github.com/CalsRanna/ant_design_flutter)
70 |
71 | Or clone locally:
72 |
73 | ```bash
74 | $ git git@github.com:CalsRanna/ant_design_flutter
75 | $ cd ant_design_flutter
76 | $ flutter pub get
77 | $ flutter run
78 | ```
79 |
80 | Now flutter will run on the connected device in your environment.
81 |
82 | ## 🤝 Contributing [](https://github.com/CalsRanna/ant_design_flutter/pulls)
83 |
84 | We welcome all contributions. You can submit any ideas as [pull requests](https://github.com/CalsRanna/ant_design_flutter/pulls) or as [GitHub issues](https://github.com/CalsRanna/ant_design_flutter/issues).
85 |
86 | [](https://issuehunt.io/r/CalsRanna/ant_design_flutter)
87 |
88 | ## ❤️ Sponsors and Backers
89 |
--------------------------------------------------------------------------------
/analysis_options.yaml:
--------------------------------------------------------------------------------
1 | include: package:flutter_lints/flutter.yaml
2 |
3 | # Additional information about this file can be found at
4 | # https://dart.dev/guides/language/analysis-options
5 |
--------------------------------------------------------------------------------
/example/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:ant_design_flutter/ant_design_flutter.dart';
2 |
3 | void main() {
4 | runApp(const MyApp());
5 | }
6 |
7 | class MyApp extends StatefulWidget {
8 | const MyApp({Key? key}) : super(key: key);
9 |
10 | @override
11 | State createState() => _MyAppState();
12 | }
13 |
14 | class _MyAppState extends State {
15 | int count = 0;
16 |
17 | @override
18 | Widget build(BuildContext context) {
19 | return AntApp(
20 | home: Scaffold(
21 | body: Center(
22 | child: Column(
23 | mainAxisAlignment: MainAxisAlignment.center,
24 | children: [
25 | Text('You have clicked the button $count times'),
26 | const SizedBox(height: 8),
27 | Button(
28 | type: ButtonType.primary,
29 | onClick: () => setState(() => count++),
30 | child: const Text('Click'),
31 | ),
32 | ],
33 | ),
34 | ),
35 | ),
36 | );
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/lib/ant_design_flutter.dart:
--------------------------------------------------------------------------------
1 | /// Flutter widget implementing Ant Design.
2 | ///
3 | /// To use, import `package:ant_design_flutter/ant_design_flutter.dart`.
4 | library ant_design_flutter;
5 |
6 | export 'package:ant_design_flutter/src/enum/placement.dart';
7 | export 'package:ant_design_flutter/src/enum/status.dart';
8 | export 'package:ant_design_flutter/src/enum/size.dart';
9 | export 'package:ant_design_flutter/src/enum/theme.dart';
10 | export 'package:ant_design_flutter/src/enum/trigger.dart';
11 |
12 | export 'package:ant_design_flutter/src/style/color.dart';
13 | export 'package:ant_design_flutter/src/style/icon.dart';
14 |
15 | export 'package:ant_design_flutter/src/widget/affix.dart';
16 | export 'package:ant_design_flutter/src/widget/alert.dart';
17 | export 'package:ant_design_flutter/src/widget/app.dart';
18 | export 'package:ant_design_flutter/src/widget/auto_complete.dart';
19 | export 'package:ant_design_flutter/src/widget/breadcrumb.dart';
20 | export 'package:ant_design_flutter/src/widget/button.dart';
21 | export 'package:ant_design_flutter/src/widget/card.dart';
22 | export 'package:ant_design_flutter/src/widget/cascader.dart';
23 | export 'package:ant_design_flutter/src/widget/checkbox.dart';
24 | export 'package:ant_design_flutter/src/widget/date_picker.dart';
25 | export 'package:ant_design_flutter/src/widget/divider.dart';
26 | export 'package:ant_design_flutter/src/widget/drawer.dart';
27 | export 'package:ant_design_flutter/src/widget/dropdown.dart';
28 | export 'package:ant_design_flutter/src/widget/icon.dart';
29 | export 'package:ant_design_flutter/src/widget/image.dart';
30 | export 'package:ant_design_flutter/src/widget/input.dart';
31 | export 'package:ant_design_flutter/src/widget/input_number.dart';
32 | export 'package:ant_design_flutter/src/widget/layout.dart';
33 | export 'package:ant_design_flutter/src/widget/modal.dart';
34 | export 'package:ant_design_flutter/src/widget/menu.dart';
35 | export 'package:ant_design_flutter/src/widget/message.dart';
36 | export 'package:ant_design_flutter/src/widget/notification.dart';
37 | export 'package:ant_design_flutter/src/widget/page_header.dart';
38 | export 'package:ant_design_flutter/src/widget/pagination.dart';
39 | export 'package:ant_design_flutter/src/widget/radio.dart';
40 | export 'package:ant_design_flutter/src/widget/scaffold.dart';
41 | export 'package:ant_design_flutter/src/widget/select.dart';
42 | export 'package:ant_design_flutter/src/widget/slider.dart';
43 | export 'package:ant_design_flutter/src/widget/space.dart';
44 | export 'package:ant_design_flutter/src/widget/steps.dart';
45 | export 'package:ant_design_flutter/src/widget/switch.dart';
46 | export 'package:ant_design_flutter/src/widget/table.dart';
47 | export 'package:ant_design_flutter/src/widget/tabs.dart';
48 | export 'package:ant_design_flutter/src/widget/tag.dart';
49 | export 'package:ant_design_flutter/src/widget/tooltip.dart';
50 | export 'package:ant_design_flutter/src/widget/typography.dart';
51 |
52 | export 'package:ant_design_flutter/src/widget/nested_gesture_detector.dart';
53 |
54 | export 'package:flutter/widgets.dart'
55 | hide Icon, Image, Notification, Size, Table;
56 |
--------------------------------------------------------------------------------
/lib/src/enum/placement.dart:
--------------------------------------------------------------------------------
1 | enum Placement {
2 | topLeft,
3 | top,
4 | topRight,
5 | rightTop,
6 | right,
7 | rightBottom,
8 | bottomRight,
9 | bottom,
10 | bottomLeft,
11 | leftBottom,
12 | left,
13 | leftTop,
14 | }
15 |
--------------------------------------------------------------------------------
/lib/src/enum/size.dart:
--------------------------------------------------------------------------------
1 | enum Size { large, middle, small }
2 |
--------------------------------------------------------------------------------
/lib/src/enum/status.dart:
--------------------------------------------------------------------------------
1 | enum Status { error, info, success, warning }
2 |
--------------------------------------------------------------------------------
/lib/src/enum/theme.dart:
--------------------------------------------------------------------------------
1 | enum Theme { light, dark }
2 |
--------------------------------------------------------------------------------
/lib/src/enum/trigger.dart:
--------------------------------------------------------------------------------
1 | enum Trigger { hover, focus, click, contextMenu }
2 |
--------------------------------------------------------------------------------
/lib/src/style/color.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/widgets.dart';
2 |
3 | class Colors {
4 | static const red_1 = Color(0xfffff1f0);
5 | static const red_2 = Color(0xffffccc7);
6 | static const red_3 = Color(0xffffa39e);
7 | static const red_4 = Color(0xffff7875);
8 | static const red_5 = Color(0xffff4d4f);
9 | static const red_6 = Color(0xfff5222d);
10 | static const red_7 = Color(0xffcf1322);
11 | static const red_8 = Color(0xffa8071a);
12 | static const red_9 = Color(0xff820014);
13 | static const red_10 = Color(0xff5c0011);
14 |
15 | static const volcano_1 = Color(0xfffff2e8);
16 | static const volcano_2 = Color(0xffffd8bf);
17 | static const volcano_3 = Color(0xffffbb96);
18 | static const volcano_4 = Color(0xffff9c6e);
19 | static const volcano_5 = Color(0xffff7a45);
20 | static const volcano_6 = Color(0xfffa541c);
21 | static const volcano_7 = Color(0xffd4380d);
22 | static const volcano_8 = Color(0xffad2102);
23 | static const volcano_9 = Color(0xff871400);
24 | static const volcano_10 = Color(0xff610b00);
25 |
26 | static const orange_1 = Color(0xfffff7e6);
27 | static const orange_2 = Color(0xffffe7ba);
28 | static const orange_3 = Color(0xffffd591);
29 | static const orange_4 = Color(0xffffc069);
30 | static const orange_5 = Color(0xffffa940);
31 | static const orange_6 = Color(0xfffa8c16);
32 | static const orange_7 = Color(0xffd46b08);
33 | static const orange_8 = Color(0xffad4e00);
34 | static const orange_9 = Color(0xff873800);
35 | static const orange_10 = Color(0xff612500);
36 |
37 | static const gold_1 = Color(0xfffffbe6);
38 | static const gold_2 = Color(0xfffff1b8);
39 | static const gold_3 = Color(0xffffe58f);
40 | static const gold_4 = Color(0xffffd666);
41 | static const gold_5 = Color(0xffffc53d);
42 | static const gold_6 = Color(0xfffaad14);
43 | static const gold_7 = Color(0xffd48806);
44 | static const gold_8 = Color(0xffad6800);
45 | static const gold_9 = Color(0xff874d00);
46 | static const gold_10 = Color(0xff613400);
47 |
48 | static const yellow_1 = Color(0xfffeffe6);
49 | static const yellow_2 = Color(0xffffffb8);
50 | static const yellow_3 = Color(0xfffffb8f);
51 | static const yellow_4 = Color(0xfffff566);
52 | static const yellow_5 = Color(0xffffec3d);
53 | static const yellow_6 = Color(0xfffadb14);
54 | static const yellow_7 = Color(0xffd4b106);
55 | static const yellow_8 = Color(0xffad8b00);
56 | static const yellow_9 = Color(0xff876800);
57 | static const yellow_10 = Color(0xff614700);
58 |
59 | static const lime_1 = Color(0xfffcffe6);
60 | static const lime_2 = Color(0xfff4ffb8);
61 | static const lime_3 = Color(0xffeaff8f);
62 | static const lime_4 = Color(0xffd3f261);
63 | static const lime_5 = Color(0xffbae637);
64 | static const lime_6 = Color(0xffa0d911);
65 | static const lime_7 = Color(0xff7cb305);
66 | static const lime_8 = Color(0xff5b8c00);
67 | static const lime_9 = Color(0xff3f6600);
68 | static const lime_10 = Color(0xff254000);
69 |
70 | static const green_1 = Color(0xfff6ffed);
71 | static const green_2 = Color(0xffd9f7be);
72 | static const green_3 = Color(0xffb7eb8f);
73 | static const green_4 = Color(0xff95de64);
74 | static const green_5 = Color(0xff73d13d);
75 | static const green_6 = Color(0xff52c41a);
76 | static const green_7 = Color(0xff389e0d);
77 | static const green_8 = Color(0xff237804);
78 | static const green_9 = Color(0xff135200);
79 | static const green_10 = Color(0xff092b00);
80 |
81 | static const cyan_1 = Color(0xffe6fffb);
82 | static const cyan_2 = Color(0xffb5f5ec);
83 | static const cyan_3 = Color(0xff87e8de);
84 | static const cyan_4 = Color(0xff5cdbd3);
85 | static const cyan_5 = Color(0xff36cfc9);
86 | static const cyan_6 = Color(0xff13c2c2);
87 | static const cyan_7 = Color(0xff08979c);
88 | static const cyan_8 = Color(0xff006d75);
89 | static const cyan_9 = Color(0xff00474f);
90 | static const cyan_10 = Color(0xff002329);
91 |
92 | static const blue_1 = Color(0xffe6f7ff);
93 | static const blue_2 = Color(0xffbae7ff);
94 | static const blue_3 = Color(0xff91d5ff);
95 | static const blue_4 = Color(0xff69c0ff);
96 | static const blue_5 = Color(0xff40a9ff);
97 | static const blue_6 = Color(0xff1890ff);
98 | static const blue_7 = Color(0xff096dd9);
99 | static const blue_8 = Color(0xff0050b3);
100 | static const blue_9 = Color(0xff003a8c);
101 | static const blue_10 = Color(0xff002766);
102 |
103 | static const geekblue_1 = Color(0xfff0f5ff);
104 | static const geekblue_2 = Color(0xffd6e4ff);
105 | static const geekblue_3 = Color(0xffadc6ff);
106 | static const geekblue_4 = Color(0xff85a5ff);
107 | static const geekblue_5 = Color(0xff597ef7);
108 | static const geekblue_6 = Color(0xff2f54eb);
109 | static const geekblue_7 = Color(0xff1d39c4);
110 | static const geekblue_8 = Color(0xff10239e);
111 | static const geekblue_9 = Color(0xff061178);
112 | static const geekblue_10 = Color(0xff030852);
113 |
114 | static const purple_1 = Color(0xfff9f0ff);
115 | static const purple_2 = Color(0xffefdbff);
116 | static const purple_3 = Color(0xffd3adf7);
117 | static const purple_4 = Color(0xffb37feb);
118 | static const purple_5 = Color(0xff9254de);
119 | static const purple_6 = Color(0xff722ed1);
120 | static const purple_7 = Color(0xff531dab);
121 | static const purple_8 = Color(0xff391085);
122 | static const purple_9 = Color(0xff22075e);
123 | static const purple_10 = Color(0xff120338);
124 |
125 | static const magenta_1 = Color(0xfffff0f6);
126 | static const magenta_2 = Color(0xffffd6e7);
127 | static const magenta_3 = Color(0xffffadd2);
128 | static const magenta_4 = Color(0xffff85c0);
129 | static const magenta_5 = Color(0xfff759ab);
130 | static const magenta_6 = Color(0xffeb2f96);
131 | static const magenta_7 = Color(0xffc41d7f);
132 | static const magenta_8 = Color(0xff9e1068);
133 | static const magenta_9 = Color(0xff780650);
134 | static const magenta_10 = Color(0xff520339);
135 |
136 | static const gray_1 = Color(0xffffffff);
137 | static const gray_2 = Color(0xfffafafa);
138 | static const gray_3 = Color(0xfff5f5f5);
139 | static const gray_4 = Color(0xfff0f0f0);
140 | static const gray_5 = Color(0xffd9d9d9);
141 | static const gray_6 = Color(0xffbfbfbf);
142 | static const gray_7 = Color(0xff8c8c8c);
143 | static const gray_8 = Color(0xff595959);
144 | static const gray_9 = Color(0xff434343);
145 | static const gray_10 = Color(0xff262626);
146 | static const gray_11 = Color(0xff1f1f1f);
147 | static const gray_12 = Color(0xff141414);
148 | static const gray_13 = Color(0xff000000);
149 |
150 | static const black = Color(0xff000000);
151 | static const transparent = Color(0x00000000);
152 | static const white = Color(0xffffffff);
153 | }
154 |
--------------------------------------------------------------------------------
/lib/src/style/icon.dart:
--------------------------------------------------------------------------------
1 | // ignore_for_file: constant_identifier_names
2 |
3 | import 'package:flutter/material.dart' as material show Icons;
4 |
5 | class Icons {
6 | /// arrow_back — material icon named "arrow left".
7 | static const arrow_left = material.Icons.arrow_back;
8 |
9 | /// arrow_forward — material icon named "arrow right".
10 | static const arrow_right = material.Icons.arrow_forward;
11 |
12 | /// check — material icon named "check".
13 | static const check = material.Icons.check;
14 |
15 | /// expand_more — material icon named "chevron down".
16 | static const chevron_down = material.Icons.expand_more;
17 |
18 | /// chevron_left — material icon named "chevron left".
19 | static const chevron_left = material.Icons.chevron_left;
20 |
21 | /// chevron_right — material icon named "chevron right".
22 | static const chevron_right = material.Icons.chevron_right;
23 |
24 | /// expand_less — material icon named "chevron up".
25 | static const chevron_up = material.Icons.expand_less;
26 |
27 | /// cancel — material icon named "clear".
28 | static const clear = material.Icons.cancel;
29 |
30 | /// close — material icon named "close".
31 | static const close = material.Icons.close;
32 |
33 | /// code — material icon named "code".
34 | static const code = material.Icons.code;
35 |
36 | /// copy_all — material icon named "copy".
37 | static const copy = material.Icons.copy_all;
38 |
39 | /// view_in_ar — material icon named "dart pad".
40 | static const dart_pad = material.Icons.view_in_ar;
41 |
42 | /// bug_report — material icon named "debug".
43 | static const debug = material.Icons.bug_report;
44 |
45 | /// download — material icon named "download".
46 | static const download = material.Icons.download;
47 |
48 | /// cancel — material icon named "error".
49 | static const error = material.Icons.cancel;
50 |
51 | /// info — material icon named "info".
52 | static const info = material.Icons.info;
53 |
54 | /// autorenew — material icon named "loading".
55 | static const loading = material.Icons.autorenew;
56 |
57 | /// power_settings_new — material icon named "power off".
58 | static const power_off = material.Icons.power_settings_new;
59 |
60 | /// search — material icon named "search".
61 | static const search = material.Icons.search;
62 |
63 | /// check_circle — material icon named "success".
64 | static const success = material.Icons.check_circle;
65 |
66 | /// error — material icon named "warning".
67 | static const warning = material.Icons.error;
68 | }
69 |
--------------------------------------------------------------------------------
/lib/src/widget/affix.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/widgets.dart';
2 |
3 | class Affix extends StatefulWidget {
4 | const Affix({
5 | Key? key,
6 | required this.child,
7 | this.offsetBottom,
8 | this.offsetTop = 0,
9 | this.target,
10 | this.onChange,
11 | }) : super(key: key);
12 |
13 | final Widget child;
14 | final double? offsetBottom;
15 | final double offsetTop;
16 | final void Function()? target;
17 | final void Function(bool affixed)? onChange;
18 |
19 | @override
20 | State createState() => _AffixState();
21 | }
22 |
23 | class _AffixState extends State {
24 | @override
25 | Widget build(BuildContext context) {
26 | return widget.child;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/lib/src/widget/alert.dart:
--------------------------------------------------------------------------------
1 | import 'package:ant_design_flutter/src/enum/status.dart';
2 | import 'package:ant_design_flutter/src/style/color.dart';
3 | import 'package:ant_design_flutter/src/style/icon.dart';
4 | import 'package:flutter/widgets.dart';
5 |
6 | class Alert extends StatefulWidget {
7 | const Alert({
8 | Key? key,
9 | this.action,
10 | this.afterClose,
11 | this.banner = false,
12 | this.closable,
13 | this.closeText,
14 | this.closeIcon = const Icon(Icons.close),
15 | this.description,
16 | this.icon,
17 | required this.message,
18 | this.showIcon = false,
19 | this.type = Status.info,
20 | this.onClose,
21 | }) : super(key: key);
22 |
23 | final Widget? action;
24 | final void Function()? afterClose;
25 | final bool banner;
26 | final bool? closable;
27 | final Widget? closeText;
28 | final Widget closeIcon;
29 | final Widget? description;
30 | final Widget? icon;
31 | final Widget message;
32 | final bool showIcon;
33 | final Status type;
34 | final void Function()? onClose;
35 |
36 | @override
37 | State createState() => _AlertState();
38 | }
39 |
40 | class _AlertState extends State {
41 | @override
42 | Widget build(BuildContext context) {
43 | return Container(
44 | decoration: BoxDecoration(
45 | border: Border.all(color: Colors.blue_3),
46 | borderRadius: BorderRadius.circular(2),
47 | color: Colors.blue_1,
48 | ),
49 | padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
50 | width: double.infinity,
51 | child: widget.message,
52 | );
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/lib/src/widget/anchor.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/anchor.dart
--------------------------------------------------------------------------------
/lib/src/widget/app.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart' show MaterialApp;
2 | import 'package:flutter/widgets.dart';
3 |
4 | /// An application that uses Ant Design.
5 | ///
6 | /// A root widget which should be used as the application entry point. It provide
7 | /// [GlobalQuery] to solve overlay entry's offset and other feature.
8 | ///
9 | /// It basic was a sub class of Material App and some few params provided to use.
10 | class AntApp extends StatefulWidget {
11 | const AntApp({
12 | Key? key,
13 | this.home,
14 | this.showPerformanceOverlay = false,
15 | }) : routeInformationParser = null,
16 | routerDelegate = null,
17 | super(key: key);
18 |
19 | const AntApp.router({
20 | Key? key,
21 | required this.showPerformanceOverlay,
22 | required this.routeInformationParser,
23 | required this.routerDelegate,
24 | }) : home = null,
25 | super(key: key);
26 |
27 | final Widget? home;
28 | final bool showPerformanceOverlay;
29 | final RouteInformationParser? routeInformationParser;
30 | final RouterDelegate? routerDelegate;
31 |
32 | @override
33 | State createState() => _AntAppState();
34 | }
35 |
36 | class _AntAppState extends State {
37 | int messageCount = 0;
38 | Map tops = {};
39 | Map notificationTops = {};
40 |
41 | @override
42 | Widget build(BuildContext context) {
43 | Widget app = MaterialApp(
44 | debugShowCheckedModeBanner: false,
45 | home: widget.home,
46 | showPerformanceOverlay: widget.showPerformanceOverlay,
47 | );
48 | if (widget.routerDelegate != null) {
49 | app = MaterialApp.router(
50 | debugShowCheckedModeBanner: false,
51 | routeInformationParser: widget.routeInformationParser!,
52 | routerDelegate: widget.routerDelegate!,
53 | showPerformanceOverlay: widget.showPerformanceOverlay,
54 | );
55 | }
56 |
57 | return GlobalQuery(
58 | tops: tops,
59 | notificationTops: notificationTops,
60 | insert: _insert,
61 | remove: _remove,
62 | insertNotification: _insertNotification,
63 | removeNotification: _removeNotification,
64 | child: app,
65 | );
66 | }
67 |
68 | void _insert(ValueKey key, double top) {
69 | setState(() {
70 | tops[key] = top;
71 | });
72 | }
73 |
74 | void _remove(ValueKey key) {
75 | setState(() {
76 | tops.remove(key);
77 | });
78 | }
79 |
80 | void _insertNotification(Key key, double top) {
81 | setState(() {
82 | notificationTops[key] = top;
83 | });
84 | }
85 |
86 | void _removeNotification(Key key) {
87 | setState(() {
88 | notificationTops.remove(key);
89 | });
90 | }
91 | }
92 |
93 | class GlobalQuery extends InheritedWidget {
94 | const GlobalQuery({
95 | Key? key,
96 | required Widget child,
97 | required this.tops,
98 | required this.notificationTops,
99 | required this.insert(ValueKey key, double top),
100 | required this.remove(ValueKey key),
101 | required this.insertNotification(Key key, double top),
102 | required this.removeNotification(Key key),
103 | }) : super(key: key, child: child);
104 |
105 | final Map tops;
106 | final Map notificationTops;
107 | final void Function(ValueKey key, double top) insert;
108 | final void Function(ValueKey key) remove;
109 | final void Function(Key key, double top) insertNotification;
110 | final void Function(Key key) removeNotification;
111 |
112 | static GlobalQuery? of(BuildContext context) {
113 | return context.dependOnInheritedWidgetOfExactType();
114 | }
115 |
116 | @override
117 | bool updateShouldNotify(GlobalQuery oldWidget) {
118 | return oldWidget.tops != tops ||
119 | oldWidget.notificationTops != notificationTops;
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/lib/src/widget/auto_complete.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/widgets.dart';
2 |
3 | class AutoComplete extends StatefulWidget {
4 | const AutoComplete(
5 | {Key? key,
6 | this.allowClear = false,
7 | this.autoFocus = false,
8 | this.backfill = false,
9 | this.chidlren,
10 | this.defaultActiveFirstOption = true,
11 | this.defaultOpen,
12 | this.defaultValue,
13 | this.disabled = false,
14 | this.dropdownMatchSelectWidth,
15 | this.filterOption = true,
16 | this.getPopupContainer,
17 | this.notFoundContent,
18 | this.open,
19 | this.options,
20 | this.placeholder,
21 | this.status,
22 | this.value,
23 | this.onBlur,
24 | this.onChange,
25 | this.onDropdownVisibleChange,
26 | this.onFocus,
27 | this.onSearch,
28 | this.onSelect,
29 | this.onClear})
30 | : super(key: key);
31 |
32 | final bool allowClear;
33 | final bool autoFocus;
34 | final bool backfill;
35 | final List? chidlren;
36 | final bool defaultActiveFirstOption;
37 | final bool? defaultOpen;
38 | final String? defaultValue;
39 | final bool disabled;
40 | final double? dropdownMatchSelectWidth;
41 | final bool filterOption;
42 | final Widget Function()? getPopupContainer;
43 | final Widget? notFoundContent;
44 | final bool? open;
45 | final List>? options;
46 | final String? placeholder;
47 | final AutoCompleteStatus? status;
48 | final String? value;
49 | final void Function()? onBlur;
50 | final void Function(String value)? onChange;
51 | final void Function(bool open)? onDropdownVisibleChange;
52 | final void Function()? onFocus;
53 | final void Function(String value)? onSearch;
54 | final void Function(String value, Map option)? onSelect;
55 | final void Function()? onClear;
56 |
57 | @override
58 | State createState() => _AutoCompleteState();
59 |
60 | void blur() {}
61 |
62 | void focus() {}
63 | }
64 |
65 | class _AutoCompleteState extends State {
66 | @override
67 | Widget build(BuildContext context) {
68 | return Container();
69 | }
70 | }
71 |
72 | enum AutoCompleteStatus { error, warning }
73 |
--------------------------------------------------------------------------------
/lib/src/widget/avatar.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/avatar.dart
--------------------------------------------------------------------------------
/lib/src/widget/badge.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/badge.dart
--------------------------------------------------------------------------------
/lib/src/widget/breadcrumb.dart:
--------------------------------------------------------------------------------
1 | import 'package:ant_design_flutter/src/style/color.dart';
2 | import 'package:flutter/widgets.dart';
3 |
4 | class Breadcrumb extends StatelessWidget {
5 | const Breadcrumb({
6 | Key? key,
7 | this.children,
8 | this.itemBuilder,
9 | this.itemCount,
10 | this.params,
11 | this.separator,
12 | }) : super(key: key);
13 |
14 | final List? children;
15 | final Widget Function(BuildContext context, int index)? itemBuilder;
16 | final int? itemCount;
17 | final Map? params;
18 | final Widget? separator;
19 |
20 | @override
21 | Widget build(BuildContext context) {
22 | return _BreadcrumbInhertedWidget(
23 | current: _getCurrent(context),
24 | child: Row(
25 | children: _buildChildren(context),
26 | ),
27 | );
28 | }
29 |
30 | List _buildChildren(BuildContext context) {
31 | var realSeparator = separator ??
32 | const Padding(
33 | padding: EdgeInsets.symmetric(horizontal: 8),
34 | child: Text(
35 | '/',
36 | style: TextStyle(color: Colors.gray_7, height: 1),
37 | ),
38 | );
39 | final List children = [];
40 | if (itemBuilder != null && itemCount != null) {
41 | for (int i = 0; i < itemCount!; i++) {
42 | children.add(itemBuilder!(context, i));
43 | if (i != itemCount! - 1) {
44 | children.add(realSeparator);
45 | }
46 | }
47 | } else {
48 | for (int i = 0; i < children.length; i++) {
49 | children.add(children[i]);
50 | if (i != children.length - 1) {
51 | children.add(realSeparator);
52 | }
53 | }
54 | }
55 | return children;
56 | }
57 |
58 | String _getCurrent(BuildContext context) {
59 | BreadcrumbItem? currentWidget;
60 | if (itemBuilder != null && itemCount != null) {
61 | currentWidget = itemBuilder!(context, itemCount! - 1) as BreadcrumbItem;
62 | } else if (children != null) {
63 | currentWidget = children![children!.length - 1] as BreadcrumbItem;
64 | }
65 | return currentWidget?.href ?? '';
66 | }
67 | }
68 |
69 | class BreadcrumbItem extends StatefulWidget {
70 | const BreadcrumbItem({
71 | Key? key,
72 | required this.child,
73 | required this.href,
74 | this.onClick,
75 | }) : super(key: key);
76 |
77 | final Widget child;
78 | final String href;
79 | final void Function()? onClick;
80 |
81 | @override
82 | State createState() => _BreadcrumbItemState();
83 | }
84 |
85 | class _BreadcrumbItemState extends State {
86 | bool hovered = false;
87 |
88 | @override
89 | Widget build(BuildContext context) {
90 | var current = _BreadcrumbInhertedWidget.of(context)!.current;
91 | return widget.href != current
92 | ? MouseRegion(
93 | cursor: SystemMouseCursors.click,
94 | onEnter: (_) {
95 | setState(() {
96 | hovered = true;
97 | });
98 | },
99 | onExit: (_) {
100 | setState(() {
101 | hovered = false;
102 | });
103 | },
104 | child: DefaultTextStyle.merge(
105 | style: TextStyle(
106 | color: hovered ? Colors.blue_6 : Colors.gray_7,
107 | ),
108 | child: widget.child,
109 | ),
110 | )
111 | : DefaultTextStyle.merge(
112 | style: const TextStyle(color: Colors.black),
113 | child: widget.child,
114 | );
115 | }
116 | }
117 |
118 | class BreadcrumbSeparator extends StatelessWidget {
119 | const BreadcrumbSeparator({Key? key, required this.child}) : super(key: key);
120 |
121 | final Widget child;
122 |
123 | @override
124 | Widget build(BuildContext context) {
125 | return const Padding(
126 | padding: EdgeInsets.symmetric(horizontal: 8),
127 | child: Text(
128 | '/',
129 | style: TextStyle(color: Colors.gray_7, height: 1),
130 | ),
131 | );
132 | }
133 | }
134 |
135 | class _BreadcrumbInhertedWidget extends InheritedWidget {
136 | const _BreadcrumbInhertedWidget({
137 | Key? key,
138 | required this.current,
139 | required Widget child,
140 | }) : super(key: key, child: child);
141 |
142 | final String current;
143 |
144 | static _BreadcrumbInhertedWidget? of(BuildContext context) {
145 | return context
146 | .dependOnInheritedWidgetOfExactType<_BreadcrumbInhertedWidget>();
147 | }
148 |
149 | @override
150 | bool updateShouldNotify(_BreadcrumbInhertedWidget oldWidget) {
151 | return oldWidget.current != current;
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/lib/src/widget/button.dart:
--------------------------------------------------------------------------------
1 | import 'package:ant_design_flutter/src/enum/size.dart';
2 | import 'package:ant_design_flutter/src/style/color.dart';
3 | import 'package:ant_design_flutter/src/style/icon.dart';
4 | import 'package:dotted_border/dotted_border.dart';
5 | import 'package:flutter/gestures.dart';
6 | import 'package:flutter/widgets.dart';
7 |
8 | /// [Button] is completely a [Container] but can be clicked.
9 | ///
10 | /// Its height is determined by [size] and [shape], and can't override.
11 | ///
12 | /// At least one of [child], [icon] must be non-null.
13 | class Button extends StatefulWidget {
14 | const Button({
15 | Key? key,
16 | this.block = false,
17 | this.danger = false,
18 | this.disabled = false,
19 | this.ghost = false,
20 | this.href,
21 | this.icon,
22 | this.loading = false,
23 | this.shape = ButtonShape.square,
24 | this.size = Size.middle,
25 | this.type = ButtonType.normal,
26 | this.onClick,
27 | this.child,
28 | }) : assert(child != null || icon != null,
29 | 'Child and icon can not be both null'),
30 | super(key: key);
31 |
32 | final bool block;
33 | final bool danger;
34 | final bool disabled;
35 | final bool ghost;
36 | final String? href;
37 | final Widget? icon;
38 | final bool loading;
39 | final ButtonShape shape;
40 | final Size size;
41 | final ButtonType type;
42 | final void Function()? onClick;
43 | final Widget? child;
44 |
45 | @override
46 | State createState() => _ButtonState();
47 | }
48 |
49 | class _ButtonState extends State with SingleTickerProviderStateMixin {
50 | late AnimationController controller;
51 | bool clicked = false;
52 | bool hovered = false;
53 |
54 | @override
55 | void initState() {
56 | controller = AnimationController(
57 | duration: const Duration(seconds: 1),
58 | vsync: this,
59 | )..repeat();
60 | super.initState();
61 | }
62 |
63 | @override
64 | void dispose() {
65 | controller.dispose();
66 | super.dispose();
67 | }
68 |
69 | @override
70 | Widget build(BuildContext context) {
71 | double height = 32;
72 | if (Size.large == widget.size) {
73 | height = 40;
74 | }
75 | if (Size.small == widget.size) {
76 | height = 24;
77 | }
78 |
79 | double padding = 15;
80 | if (Size.small == widget.size) {
81 | padding = 7;
82 | }
83 | if (null != widget.icon && null == widget.child) {
84 | padding = (height - 16) / 2;
85 | if (ButtonShape.round == widget.shape) {
86 | padding = padding + 8;
87 | }
88 | }
89 |
90 | BorderRadius? borderRadius = BorderRadius.circular(2);
91 | if (ButtonShape.circle == widget.shape) {
92 | borderRadius = null;
93 | }
94 | if (ButtonShape.round == widget.shape) {
95 | borderRadius = BorderRadius.circular(height / 2);
96 | }
97 |
98 | MouseCursor cursor = SystemMouseCursors.click;
99 | if (widget.disabled || widget.loading) {
100 | cursor = SystemMouseCursors.forbidden;
101 | }
102 |
103 | Map colors = calculateColors();
104 |
105 | BoxShape shape = widget.shape == ButtonShape.circle
106 | ? BoxShape.circle
107 | : BoxShape.rectangle;
108 |
109 | Radius radius = const Radius.circular(2);
110 | if (ButtonShape.circle == widget.shape) {
111 | radius = const Radius.circular(0);
112 | }
113 | if (ButtonShape.round == widget.shape) {
114 | radius = Radius.circular(height / 2);
115 | }
116 |
117 | Widget content = buildContent();
118 |
119 | Widget dashedButton = DottedBorder(
120 | color: colors['border']!,
121 | borderType: widget.shape == ButtonShape.circle
122 | ? BorderType.Circle
123 | : BorderType.RRect,
124 | dashPattern: const [3, 3],
125 | padding: const EdgeInsets.all(0),
126 | radius: radius,
127 | child: Container(
128 | alignment: Alignment.center,
129 | decoration: BoxDecoration(color: colors['content'], shape: shape),
130 | height: height,
131 | padding: EdgeInsets.symmetric(horizontal: padding),
132 | child: content,
133 | ),
134 | );
135 |
136 | Widget normalButton = Container(
137 | alignment: Alignment.center,
138 | decoration: BoxDecoration(
139 | color: colors['content'],
140 | border: Border.all(color: colors['border']!),
141 | borderRadius: borderRadius,
142 | shape: shape,
143 | ),
144 | height: height,
145 | padding: EdgeInsets.symmetric(horizontal: padding),
146 | child: content,
147 | );
148 |
149 | Widget child =
150 | widget.type == ButtonType.dashed ? dashedButton : normalButton;
151 | if (!widget.block) {
152 | child = UnconstrainedBox(child: child);
153 | }
154 |
155 | return DefaultTextStyle.merge(
156 | style: TextStyle(color: colors['text'], fontSize: 14, height: 1),
157 | child: IconTheme(
158 | data: IconThemeData(color: colors['text'], size: 16),
159 | child: MouseRegion(
160 | cursor: cursor,
161 | onEnter: handleEnter,
162 | onExit: handleExit,
163 | child: GestureDetector(
164 | onTapDown: handleTapDown,
165 | onTapUp: handleTapUp,
166 | child: child,
167 | ),
168 | ),
169 | ),
170 | );
171 | }
172 |
173 | Widget buildContent() {
174 | Widget? loadingIcon = RotationTransition(
175 | turns: controller,
176 | child: const Icon(Icons.loading),
177 | );
178 |
179 | if (widget.child != null && widget.icon != null) {
180 | return Row(
181 | mainAxisSize: MainAxisSize.min,
182 | children: [
183 | widget.loading ? loadingIcon : widget.icon!,
184 | const SizedBox(width: 8),
185 | widget.child!,
186 | ],
187 | );
188 | } else {
189 | if (widget.child != null && widget.icon == null) {
190 | return Row(
191 | mainAxisSize: MainAxisSize.min,
192 | children: [
193 | if (widget.loading) loadingIcon,
194 | if (widget.loading) const SizedBox(width: 8),
195 | widget.child!,
196 | ],
197 | );
198 | } else {
199 | return widget.loading ? loadingIcon : widget.icon!;
200 | }
201 | }
202 | }
203 |
204 | final borderColors = {
205 | ButtonType.dashed: Colors.gray_5,
206 | ButtonType.link: Colors.gray_1,
207 | ButtonType.normal: Colors.gray_5,
208 | ButtonType.primary: Colors.blue_6,
209 | ButtonType.text: Colors.gray_1,
210 | };
211 | final contentColors = {
212 | ButtonType.dashed: Colors.gray_1,
213 | ButtonType.link: Colors.gray_1,
214 | ButtonType.normal: Colors.gray_1,
215 | ButtonType.primary: Colors.blue_6,
216 | ButtonType.text: Colors.gray_1,
217 | };
218 | final textColors = {
219 | ButtonType.dashed: Colors.gray_10,
220 | ButtonType.link: Colors.blue_6,
221 | ButtonType.normal: Colors.gray_10,
222 | ButtonType.primary: Colors.gray_1,
223 | ButtonType.text: Colors.gray_10,
224 | };
225 | final clickedBorderColors = {
226 | ButtonType.dashed: Colors.blue_7,
227 | ButtonType.link: Colors.gray_1,
228 | ButtonType.normal: Colors.blue_7,
229 | ButtonType.primary: Colors.blue_7,
230 | ButtonType.text: Colors.gray_3,
231 | };
232 | final clickedContetColors = {
233 | ButtonType.dashed: Colors.gray_1,
234 | ButtonType.link: Colors.gray_1,
235 | ButtonType.normal: Colors.gray_1,
236 | ButtonType.primary: Colors.blue_7,
237 | ButtonType.text: Colors.gray_3,
238 | };
239 | final clickedTextColors = {
240 | ButtonType.dashed: Colors.blue_7,
241 | ButtonType.link: Colors.blue_7,
242 | ButtonType.normal: Colors.blue_7,
243 | ButtonType.primary: Colors.gray_1,
244 | ButtonType.text: Colors.gray_10,
245 | };
246 | final hoverdBorderColors = {
247 | ButtonType.dashed: Colors.blue_5,
248 | ButtonType.link: Colors.gray_1,
249 | ButtonType.normal: Colors.blue_5,
250 | ButtonType.primary: Colors.blue_5,
251 | ButtonType.text: Colors.gray_2,
252 | };
253 | final hoverdContetColors = {
254 | ButtonType.dashed: Colors.gray_1,
255 | ButtonType.link: Colors.gray_1,
256 | ButtonType.normal: Colors.gray_1,
257 | ButtonType.primary: Colors.blue_5,
258 | ButtonType.text: Colors.gray_2,
259 | };
260 | final hoverdTextColors = {
261 | ButtonType.dashed: Colors.blue_5,
262 | ButtonType.link: Colors.blue_6,
263 | ButtonType.normal: Colors.blue_5,
264 | ButtonType.primary: Colors.gray_1,
265 | ButtonType.text: Colors.gray_10,
266 | };
267 | Map calculateColors() {
268 | var colors = {
269 | 'border': borderColors[widget.type],
270 | 'content': contentColors[widget.type],
271 | 'text': textColors[widget.type],
272 | };
273 | if (clicked) {
274 | colors['border'] = clickedBorderColors[widget.type];
275 | colors['content'] = clickedContetColors[widget.type];
276 | colors['text'] = clickedTextColors[widget.type];
277 | } else if (hovered || widget.loading) {
278 | colors['border'] = hoverdBorderColors[widget.type];
279 | colors['content'] = hoverdContetColors[widget.type];
280 | colors['text'] = hoverdTextColors[widget.type];
281 | }
282 | return colors;
283 | }
284 |
285 | void handleEnter(PointerEnterEvent event) {
286 | if (!widget.disabled && !widget.loading) {
287 | setState(() => hovered = true);
288 | }
289 | }
290 |
291 | void handleExit(PointerExitEvent event) {
292 | if (!widget.disabled && !widget.loading) {
293 | setState(() => hovered = false);
294 | }
295 | }
296 |
297 | void handleTapDown(TapDownDetails details) {
298 | if (!widget.disabled && !widget.loading) {
299 | setState(() {
300 | clicked = true;
301 | });
302 | }
303 | }
304 |
305 | void handleTapUp(TapUpDetails details) {
306 | if (!widget.disabled && !widget.loading) {
307 | setState(() {
308 | clicked = false;
309 | });
310 | if (widget.onClick != null) {
311 | widget.onClick!();
312 | }
313 | }
314 | }
315 | }
316 |
317 | enum ButtonShape { circle, round, square }
318 |
319 | enum ButtonType { dashed, ghost, link, normal, primary, text }
320 |
--------------------------------------------------------------------------------
/lib/src/widget/calendar.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/calendar.dart
--------------------------------------------------------------------------------
/lib/src/widget/card.dart:
--------------------------------------------------------------------------------
1 | import 'package:ant_design_flutter/src/enum/size.dart';
2 | import 'package:ant_design_flutter/src/style/color.dart';
3 | import 'package:flutter/widgets.dart';
4 |
5 | class Card extends StatefulWidget {
6 | const Card({
7 | Key? key,
8 | required this.child,
9 | this.extra,
10 | this.hoverable = false,
11 | this.size = Size.middle,
12 | this.title,
13 | }) : super(key: key);
14 |
15 | final Widget child;
16 | final Widget? extra;
17 | final bool hoverable;
18 | final Size size;
19 | final Widget? title;
20 |
21 | @override
22 | State createState() => _CardState();
23 | }
24 |
25 | class _CardState extends State {
26 | bool hovered = false;
27 |
28 | @override
29 | Widget build(BuildContext context) {
30 | Widget header = const SizedBox();
31 | if (widget.title != null || widget.extra != null) {
32 | Widget title = DefaultTextStyle.merge(
33 | child: Container(child: widget.title),
34 | style: const TextStyle(
35 | fontWeight: FontWeight.w500,
36 | overflow: TextOverflow.ellipsis,
37 | ),
38 | );
39 |
40 | Widget extra = DefaultTextStyle.merge(
41 | child: Container(child: widget.extra),
42 | style: const TextStyle(
43 | color: Colors.blue_6,
44 | overflow: TextOverflow.ellipsis,
45 | ),
46 | );
47 |
48 | header = Container(
49 | decoration: const BoxDecoration(
50 | border: Border(bottom: BorderSide(color: Colors.gray_4)),
51 | ),
52 | padding: EdgeInsets.all(
53 | Size.middle == widget.size ? 24 : 12,
54 | ),
55 | child: Row(
56 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
57 | children: [title, extra],
58 | ),
59 | );
60 | }
61 |
62 | Widget body = Padding(
63 | padding: EdgeInsets.all(Size.middle == widget.size ? 24 : 12),
64 | child: widget.child,
65 | );
66 |
67 | List? boxShadow;
68 | if (hovered) {
69 | boxShadow = const [
70 | BoxShadow(
71 | blurRadius: 4,
72 | color: Colors.gray_3,
73 | offset: Offset(4, 4),
74 | spreadRadius: 0.1,
75 | ),
76 | BoxShadow(
77 | blurRadius: 4,
78 | color: Colors.gray_3,
79 | offset: Offset(-4, 0),
80 | spreadRadius: 0.1,
81 | ),
82 | ];
83 | }
84 |
85 | return MouseRegion(
86 | cursor: SystemMouseCursors.click,
87 | onEnter: (_) => setState(() => hovered = true),
88 | onExit: (_) => setState(() => hovered = false),
89 | child: Container(
90 | decoration: BoxDecoration(
91 | border: Border.all(color: Colors.gray_4),
92 | borderRadius: BorderRadius.circular(2),
93 | boxShadow: boxShadow,
94 | color: Colors.white,
95 | ),
96 | child: Column(
97 | crossAxisAlignment: CrossAxisAlignment.start,
98 | children: [header, body],
99 | ),
100 | ),
101 | );
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/lib/src/widget/carousel.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/carousel.dart
--------------------------------------------------------------------------------
/lib/src/widget/cascader.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/widgets.dart';
2 |
3 | class Cascader extends StatefulWidget {
4 | const Cascader(
5 | {Key? key,
6 | this.allowClear = true,
7 | this.autoFocus = false,
8 | this.bordered = true,
9 | this.changeOnSelect = false,
10 | this.defaultValue = const [],
11 | this.disabled = false,
12 | this.displayBuilder,
13 | this.dropdownBuilder,
14 | this.expandIcon,
15 | this.expandTrigger = CascaderTrigger.click,
16 | this.fieldNames,
17 | this.getPopupContainer,
18 | this.loadData,
19 | this.maxTagCount,
20 | this.maxTagPlaceholder,
21 | this.notFoundContent = const Text('Not Found'),
22 | this.open,
23 | this.options = const [],
24 | this.placeholder = '请选择',
25 | this.placement = Alignment.bottomLeft,
26 | this.showSearch,
27 | this.size = CascaderSize.middle,
28 | this.status,
29 | this.suffixIcon,
30 | this.tagBuilder,
31 | this.value,
32 | this.onChange,
33 | this.onPopupVisibleChange,
34 | this.multiple,
35 | this.searchValue,
36 | this.onSearch})
37 | : super(key: key);
38 |
39 | final bool allowClear;
40 | final bool autoFocus;
41 | final bool bordered;
42 | final bool changeOnSelect;
43 | final List defaultValue;
44 | final bool disabled;
45 | final Widget Function(
46 | String label,
47 | List selectedOptions,
48 | )? displayBuilder;
49 | final Widget Function(List menus)? dropdownBuilder;
50 | final Widget? expandIcon;
51 | final CascaderTrigger expandTrigger;
52 | final Map? fieldNames;
53 | final Widget Function()? getPopupContainer;
54 | final void Function(List selectedOptions)? loadData;
55 | final int? maxTagCount;
56 | final Widget? maxTagPlaceholder;
57 | final Widget notFoundContent;
58 | final bool? open;
59 | final List options;
60 | final String placeholder;
61 | final Alignment placement;
62 | final ShowSearch? showSearch;
63 | final CascaderSize size;
64 | final CascaderStatus? status;
65 | final Widget? suffixIcon;
66 | final Widget Function()? tagBuilder;
67 | final List? value;
68 | final void Function(
69 | String value,
70 | List selectedOptions,
71 | )? onChange;
72 | final void Function(String value)? onPopupVisibleChange;
73 | final bool? multiple;
74 | final String? searchValue;
75 | final void Function(String search)? onSearch;
76 |
77 | @override
78 | State createState() => _CascaderState();
79 |
80 | void blur() {}
81 |
82 | void focus() {}
83 | }
84 |
85 | class _CascaderState extends State {
86 | @override
87 | Widget build(BuildContext context) {
88 | return Container();
89 | }
90 | }
91 |
92 | class CascaderOption {
93 | CascaderOption({
94 | required this.value,
95 | this.label,
96 | this.disabled,
97 | this.children,
98 | this.isLeaf,
99 | });
100 |
101 | String value;
102 | Widget? label;
103 | bool? disabled;
104 | List? children;
105 | bool? isLeaf;
106 | }
107 |
108 | enum CascaderTrigger { click, hover }
109 |
110 | class ShowSearch {
111 | ShowSearch({
112 | required this.filter,
113 | this.limit = 50,
114 | this.matchInputWidth = true,
115 | this.builder,
116 | this.sort,
117 | });
118 |
119 | bool Function(String inputValue, String path) filter;
120 | int limit;
121 | bool matchInputWidth;
122 | Widget Function(String inputValue, String path)? builder;
123 | void Function(String a, String b, String inputValue)? sort;
124 | }
125 |
126 | enum CascaderSize { large, middle, small }
127 |
128 | enum CascaderStatus { error, warning }
129 |
--------------------------------------------------------------------------------
/lib/src/widget/checkbox.dart:
--------------------------------------------------------------------------------
1 | import 'package:ant_design_flutter/src/style/color.dart';
2 | import 'package:ant_design_flutter/src/style/icon.dart';
3 | import 'package:flutter/widgets.dart';
4 |
5 | class Checkbox extends StatefulWidget {
6 | const Checkbox({
7 | Key? key,
8 | this.controller,
9 | this.child,
10 | this.autoFocus = false,
11 | this.checked = false,
12 | this.defaultChecked = false,
13 | this.disabled = false,
14 | this.indeterminate = false,
15 | this.onChange,
16 | }) : super(key: key);
17 |
18 | final CheckboxController? controller;
19 | final Widget? child;
20 | final bool autoFocus;
21 | final bool checked;
22 | final bool defaultChecked;
23 | final bool disabled;
24 | final bool indeterminate;
25 | final void Function()? onChange;
26 |
27 | @override
28 | State createState() => _CheckboxState();
29 | }
30 |
31 | class _CheckboxState extends State {
32 | bool hovered = false;
33 | bool checked = false;
34 |
35 | @override
36 | void initState() {
37 | super.initState();
38 | setState(() {
39 | checked = widget.controller?.checked ?? false;
40 | });
41 | }
42 |
43 | @override
44 | Widget build(BuildContext context) {
45 | return MouseRegion(
46 | cursor: SystemMouseCursors.click,
47 | onEnter: (_) => setState(() {
48 | hovered = true;
49 | }),
50 | onExit: (_) => setState(() {
51 | hovered = false;
52 | }),
53 | child: GestureDetector(
54 | onTap: _handleTap,
55 | child: Row(
56 | children: [
57 | Stack(
58 | children: [
59 | Container(
60 | decoration: BoxDecoration(
61 | border: Border.all(
62 | color: hovered ? Colors.blue_6 : Colors.gray_5,
63 | ),
64 | borderRadius: BorderRadiusDirectional.circular(2),
65 | ),
66 | width: 16,
67 | height: 16,
68 | ),
69 | checked
70 | ? Container(
71 | decoration: BoxDecoration(
72 | borderRadius: BorderRadiusDirectional.circular(2),
73 | color: Colors.blue_6,
74 | ),
75 | height: 16,
76 | width: 16,
77 | child: const Center(
78 | child: Icon(
79 | Icons.check,
80 | color: Colors.white,
81 | size: 12,
82 | ),
83 | ),
84 | )
85 | : const SizedBox(),
86 | ],
87 | ),
88 | widget.child != null
89 | ? Padding(
90 | padding: const EdgeInsets.symmetric(horizontal: 8.0),
91 | child: widget.child!,
92 | )
93 | : const SizedBox(),
94 | ],
95 | ),
96 | ),
97 | );
98 | }
99 |
100 | void _handleTap() {
101 | setState(() {
102 | checked = !checked;
103 | });
104 | widget.controller?.checked = checked;
105 | if (widget.onChange != null) {
106 | widget.onChange!();
107 | }
108 | }
109 | }
110 |
111 | class CheckboxController extends ChangeNotifier {
112 | bool checked = false;
113 | }
114 |
115 | class CheckboxGroup extends StatefulWidget {
116 | const CheckboxGroup({
117 | Key? key,
118 | required this.children,
119 | this.defaultValue = const [],
120 | this.disabled = false,
121 | this.name,
122 | this.options = const [],
123 | this.value = const [],
124 | this.onChange,
125 | }) : super(key: key);
126 |
127 | final List children;
128 | final List defaultValue;
129 | final bool disabled;
130 | final String? name;
131 | final List options;
132 | final List value;
133 | final void Function(List checkedValue)? onChange;
134 |
135 | @override
136 | State createState() => _CheckboxGroupState();
137 |
138 | void blur() {}
139 |
140 | void focus() {}
141 | }
142 |
143 | class _CheckboxGroupState extends State {
144 | @override
145 | Widget build(BuildContext context) {
146 | return Container();
147 | }
148 | }
149 |
150 | class CheckboxOption {
151 | CheckboxOption({required this.label, required this.value, this.disabled});
152 |
153 | String label;
154 | String value;
155 | bool? disabled;
156 | }
157 |
--------------------------------------------------------------------------------
/lib/src/widget/collapse.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/collapse.dart
--------------------------------------------------------------------------------
/lib/src/widget/color_picker.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/color_picker.dart
--------------------------------------------------------------------------------
/lib/src/widget/config_provider.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/config_provider.dart
--------------------------------------------------------------------------------
/lib/src/widget/date_picker.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/widgets.dart';
2 |
3 | class DatePicker extends StatefulWidget {
4 | const DatePicker({
5 | Key? key,
6 | this.allowClear = true,
7 | this.autoFocus = false,
8 | this.bordered = true,
9 | this.dateBuilder,
10 | this.disabled = false,
11 | this.disabledDate,
12 | this.getPopupContainer,
13 | this.inputReadOnly = false,
14 | this.mode,
15 | this.nextIcon,
16 | this.open,
17 | this.panelBuilder,
18 | this.picker = Picker.date,
19 | this.placeholder,
20 | this.placement = Alignment.bottomLeft,
21 | this.prevIcon,
22 | this.size = DatePickerSize.middle,
23 | this.status,
24 | this.suffixIcon,
25 | this.superNextIcon,
26 | this.superPrevIcon,
27 | this.onOpenChange,
28 | this.onPanelChange,
29 | this.defaultPickerValue,
30 | this.defaultValue,
31 | this.disabledTime,
32 | this.format = 'YYYY-MM-DD',
33 | this.extraFooterBuilder,
34 | this.showNow,
35 | this.showTime,
36 | this.showToday = true,
37 | this.value,
38 | this.onChange,
39 | this.onOk,
40 | }) : monthCellBuilder = null,
41 | super(key: key);
42 |
43 | const DatePicker.year({
44 | Key? key,
45 | this.allowClear = true,
46 | this.autoFocus = false,
47 | this.bordered = true,
48 | this.dateBuilder,
49 | this.disabled = false,
50 | this.disabledDate,
51 | this.getPopupContainer,
52 | this.inputReadOnly = false,
53 | this.mode,
54 | this.nextIcon,
55 | this.open,
56 | this.panelBuilder,
57 | this.picker = Picker.date,
58 | this.placeholder,
59 | this.placement = Alignment.bottomLeft,
60 | this.prevIcon,
61 | this.size = DatePickerSize.middle,
62 | this.status,
63 | this.suffixIcon,
64 | this.superNextIcon,
65 | this.superPrevIcon,
66 | this.onOpenChange,
67 | this.onPanelChange,
68 | this.defaultPickerValue,
69 | this.defaultValue,
70 | this.format = 'YYYY',
71 | this.extraFooterBuilder,
72 | this.value,
73 | this.onChange,
74 | }) : disabledTime = null,
75 | showNow = null,
76 | showTime = null,
77 | showToday = false,
78 | onOk = null,
79 | monthCellBuilder = null,
80 | super(key: key);
81 |
82 | const DatePicker.quarter({
83 | Key? key,
84 | this.allowClear = true,
85 | this.autoFocus = false,
86 | this.bordered = true,
87 | this.dateBuilder,
88 | this.disabled = false,
89 | this.disabledDate,
90 | this.getPopupContainer,
91 | this.inputReadOnly = false,
92 | this.mode,
93 | this.nextIcon,
94 | this.open,
95 | this.panelBuilder,
96 | this.picker = Picker.date,
97 | this.placeholder,
98 | this.placement = Alignment.bottomLeft,
99 | this.prevIcon,
100 | this.size = DatePickerSize.middle,
101 | this.status,
102 | this.suffixIcon,
103 | this.superNextIcon,
104 | this.superPrevIcon,
105 | this.onOpenChange,
106 | this.onPanelChange,
107 | this.defaultPickerValue,
108 | this.defaultValue,
109 | this.format = 'YYYY-QQ',
110 | this.extraFooterBuilder,
111 | this.value,
112 | this.onChange,
113 | }) : disabledTime = null,
114 | showNow = null,
115 | showTime = null,
116 | showToday = false,
117 | onOk = null,
118 | monthCellBuilder = null,
119 | super(key: key);
120 |
121 | const DatePicker.month({
122 | Key? key,
123 | this.allowClear = true,
124 | this.autoFocus = false,
125 | this.bordered = true,
126 | this.dateBuilder,
127 | this.disabled = false,
128 | this.disabledDate,
129 | this.getPopupContainer,
130 | this.inputReadOnly = false,
131 | this.mode,
132 | this.nextIcon,
133 | this.open,
134 | this.panelBuilder,
135 | this.picker = Picker.date,
136 | this.placeholder,
137 | this.placement = Alignment.bottomLeft,
138 | this.prevIcon,
139 | this.size = DatePickerSize.middle,
140 | this.status,
141 | this.suffixIcon,
142 | this.superNextIcon,
143 | this.superPrevIcon,
144 | this.onOpenChange,
145 | this.onPanelChange,
146 | this.defaultPickerValue,
147 | this.defaultValue,
148 | this.format = 'YYYY-MM',
149 | this.monthCellBuilder,
150 | this.extraFooterBuilder,
151 | this.value,
152 | this.onChange,
153 | }) : disabledTime = null,
154 | showNow = null,
155 | showTime = null,
156 | showToday = false,
157 | onOk = null,
158 | super(key: key);
159 |
160 | const DatePicker.week({
161 | Key? key,
162 | this.allowClear = true,
163 | this.autoFocus = false,
164 | this.bordered = true,
165 | this.dateBuilder,
166 | this.disabled = false,
167 | this.disabledDate,
168 | this.getPopupContainer,
169 | this.inputReadOnly = false,
170 | this.mode,
171 | this.nextIcon,
172 | this.open,
173 | this.panelBuilder,
174 | this.picker = Picker.date,
175 | this.placeholder,
176 | this.placement = Alignment.bottomLeft,
177 | this.prevIcon,
178 | this.size = DatePickerSize.middle,
179 | this.status,
180 | this.suffixIcon,
181 | this.superNextIcon,
182 | this.superPrevIcon,
183 | this.onOpenChange,
184 | this.onPanelChange,
185 | this.defaultPickerValue,
186 | this.defaultValue,
187 | this.format = 'YYYY-WW',
188 | this.extraFooterBuilder,
189 | this.value,
190 | this.onChange,
191 | }) : disabledTime = null,
192 | showNow = null,
193 | showTime = null,
194 | showToday = false,
195 | onOk = null,
196 | monthCellBuilder = null,
197 | super(key: key);
198 |
199 | final bool allowClear;
200 | final bool autoFocus;
201 | final bool bordered;
202 | final Widget Function(DateTime currentDate, DateTime today)? dateBuilder;
203 | final bool disabled;
204 | final bool Function(DateTime currentDate)? disabledDate;
205 | final Widget Function()? getPopupContainer;
206 | final bool inputReadOnly;
207 | final DatePickerMode? mode;
208 | final Widget? nextIcon;
209 | final bool? open;
210 | final Widget Function()? panelBuilder;
211 | final Picker picker;
212 | final String? placeholder;
213 | final Alignment placement;
214 | final Widget? prevIcon;
215 | final DatePickerSize size;
216 | final DatePickerStatus? status;
217 | final Widget? suffixIcon;
218 | final Widget? superNextIcon;
219 | final Widget? superPrevIcon;
220 | final void Function(bool open)? onOpenChange;
221 | final void Function(DateTime value, DatePickerMode mode)? onPanelChange;
222 | final DateTime? defaultPickerValue;
223 | final DateTime? defaultValue;
224 | final bool Function(DateTime date)? disabledTime;
225 | final String format;
226 | final Widget Function(DatePickerMode mode)? extraFooterBuilder;
227 | final bool? showNow;
228 | final bool? showTime;
229 | final bool showToday;
230 | final DateTime? value;
231 | final void Function(DateTime date, String dateString)? onChange;
232 | final void Function()? onOk;
233 | final void Function(DateTime date)? monthCellBuilder;
234 |
235 | @override
236 | State createState() => _DatePickerState();
237 | }
238 |
239 | class _DatePickerState extends State {
240 | @override
241 | Widget build(BuildContext context) {
242 | return Container();
243 | }
244 | }
245 |
246 | enum DatePickerMode { time, date, month, year, decade }
247 |
248 | enum Picker { date, week, month, quarter, year }
249 |
250 | enum DatePickerSize { large, middle, small }
251 |
252 | enum DatePickerStatus { error, warning }
253 |
254 | class RangePicker extends StatefulWidget {
255 | const RangePicker({
256 | Key? key,
257 | this.allowClear = true,
258 | this.autoFocus = false,
259 | this.bordered = true,
260 | this.dateBuilder,
261 | this.disabled = const [],
262 | this.disabledDate,
263 | this.getPopupContainer,
264 | this.inputReadOnly = false,
265 | this.mode,
266 | this.nextIcon,
267 | this.open,
268 | this.panelBuilder,
269 | this.picker = Picker.date,
270 | this.placeholder,
271 | this.placement = Alignment.bottomLeft,
272 | this.prevIcon,
273 | this.size = DatePickerSize.middle,
274 | this.status,
275 | this.suffixIcon,
276 | this.superNextIcon,
277 | this.superPrevIcon,
278 | this.onOpenChange,
279 | this.onPanelChange,
280 | this.allowEmpty = const [false, false],
281 | this.defaultPickerValue = const [],
282 | this.defaultValue = const [],
283 | this.disabledTime,
284 | this.format = 'YYYY-MM-DD HH:mm:ss',
285 | this.ranges,
286 | this.extraFooterBuilder,
287 | this.separator,
288 | this.showTime,
289 | this.value,
290 | this.onCalendarChange,
291 | this.onChange,
292 | }) : super(key: key);
293 |
294 | final bool allowClear;
295 | final bool autoFocus;
296 | final bool bordered;
297 | final Widget Function(
298 | DateTime currentDate, DateTime today, RangePickerInfo info)? dateBuilder;
299 | final List disabled;
300 | final bool Function(DateTime currentDate)? disabledDate;
301 | final Widget Function()? getPopupContainer;
302 | final bool inputReadOnly;
303 | final DatePickerMode? mode;
304 | final Widget? nextIcon;
305 | final bool? open;
306 | final Widget Function()? panelBuilder;
307 | final Picker picker;
308 | final String? placeholder;
309 | final Alignment placement;
310 | final Widget? prevIcon;
311 | final DatePickerSize size;
312 | final DatePickerStatus? status;
313 | final Widget? suffixIcon;
314 | final Widget? superNextIcon;
315 | final Widget? superPrevIcon;
316 | final void Function(bool open)? onOpenChange;
317 | final void Function(DateTime value, DatePickerMode mode)? onPanelChange;
318 | final List allowEmpty;
319 | final List defaultPickerValue;
320 | final List defaultValue;
321 | final bool Function(DateTime date, RangePickerPartical partical)?
322 | disabledTime;
323 | final String format;
324 | final List? ranges;
325 | final Widget Function(DatePickerMode mode)? extraFooterBuilder;
326 | final Widget? separator;
327 | final bool? showTime;
328 | final List? value;
329 | final void Function(
330 | List dates,
331 | List dateStrings,
332 | RangePickerInfo info,
333 | )? onCalendarChange;
334 | final void Function(List dates, List dateStrings)? onChange;
335 |
336 | @override
337 | State createState() => _RangePickerState();
338 | }
339 |
340 | class _RangePickerState extends State {
341 | @override
342 | Widget build(BuildContext context) {
343 | return Container();
344 | }
345 | }
346 |
347 | class RangePickerInfo {
348 | RangePickerInfo({required this.info});
349 |
350 | RangePickerPartical info;
351 | }
352 |
353 | enum RangePickerPartical { start, end }
354 |
--------------------------------------------------------------------------------
/lib/src/widget/descriptions.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/descriptions.dart
--------------------------------------------------------------------------------
/lib/src/widget/divider.dart:
--------------------------------------------------------------------------------
1 | import 'package:ant_design_flutter/src/style/color.dart';
2 | import 'package:flutter/widgets.dart';
3 |
4 | class Divider extends StatelessWidget {
5 | const Divider({
6 | Key? key,
7 | this.child,
8 | this.children,
9 | this.dashed = false,
10 | this.orientation = DividerOrientation.center,
11 | this.orientationMargin,
12 | this.plain = false,
13 | this.type = Axis.horizontal,
14 | }) : super(key: key);
15 |
16 | final Widget? child;
17 | final Widget? children;
18 | final bool dashed;
19 | final DividerOrientation orientation;
20 | final double? orientationMargin;
21 | final bool plain;
22 | final Axis type;
23 |
24 | @override
25 | Widget build(BuildContext context) {
26 | return Row(
27 | crossAxisAlignment: CrossAxisAlignment.center,
28 | children: [
29 | Container(
30 | decoration: const BoxDecoration(
31 | border: Border(
32 | bottom: BorderSide(color: Colors.gray_4),
33 | ),
34 | ),
35 | width: 24,
36 | ),
37 | child == null
38 | ? const SizedBox()
39 | : Padding(
40 | padding: const EdgeInsets.symmetric(horizontal: 12),
41 | child: DefaultTextStyle.merge(
42 | child: child!,
43 | style: const TextStyle(
44 | fontWeight: FontWeight.w500,
45 | ),
46 | ),
47 | ),
48 | Expanded(
49 | child: Container(
50 | decoration: const BoxDecoration(
51 | border: Border(
52 | bottom: BorderSide(color: Colors.gray_4),
53 | ),
54 | ),
55 | ),
56 | )
57 | ],
58 | );
59 | }
60 | }
61 |
62 | enum DividerOrientation { left, right, center }
63 |
--------------------------------------------------------------------------------
/lib/src/widget/drawer.dart:
--------------------------------------------------------------------------------
1 | import 'package:ant_design_flutter/src/enum/placement.dart';
2 | import 'package:ant_design_flutter/src/enum/size.dart';
3 | import 'package:ant_design_flutter/src/style/color.dart';
4 | import 'package:ant_design_flutter/src/style/icon.dart';
5 | import 'package:flutter/material.dart' show Material;
6 | import 'package:flutter/widgets.dart';
7 |
8 | class Drawer {
9 | Drawer(
10 | BuildContext context, {
11 | this.key,
12 | this.autoFocus = true,
13 | this.afterVisibleChange,
14 | this.child,
15 | this.closable = true,
16 | this.closeIcon,
17 | this.destroyOnClose = false,
18 | this.extra,
19 | this.footer,
20 | this.forceRender = false,
21 | this.height,
22 | this.keyboard = true,
23 | this.mask = true,
24 | this.maskClosable = true,
25 | this.placement = Placement.right,
26 | this.size = Size.middle,
27 | this.title,
28 | this.width,
29 | this.onClose,
30 | }) {
31 | _state = Overlay.of(context);
32 | _entry = OverlayEntry(
33 | builder: (_) => _Drawer(
34 | closable: closable,
35 | closeIcon: closeIcon,
36 | extra: extra,
37 | footer: footer,
38 | height: height,
39 | keyboard: keyboard,
40 | mask: mask,
41 | maskClosable: maskClosable,
42 | placement: placement,
43 | size: size,
44 | title: title,
45 | width: width,
46 | onClose: _handleClose,
47 | child: child,
48 | ),
49 | );
50 | _state?.insert(_entry!);
51 | afterVisibleChange?.call(true);
52 | }
53 |
54 | final Key? key;
55 | final bool autoFocus;
56 | final void Function(bool visible)? afterVisibleChange;
57 | final Widget? child;
58 | final bool closable;
59 | final Widget? closeIcon;
60 | final bool destroyOnClose;
61 | final Widget? extra;
62 | final Widget? footer;
63 | final bool forceRender;
64 | final double? height;
65 | final bool keyboard;
66 | final bool mask;
67 | final bool maskClosable;
68 | final Placement placement;
69 | final Size size;
70 | final Widget? title;
71 | final double? width;
72 | final void Function()? onClose;
73 |
74 | OverlayState? _state;
75 | OverlayEntry? _entry;
76 |
77 | void _handleClose() {
78 | _entry?.remove();
79 | afterVisibleChange?.call(false);
80 | onClose?.call();
81 | }
82 | }
83 |
84 | class _Drawer extends StatefulWidget {
85 | const _Drawer({
86 | Key? key,
87 | this.child,
88 | required this.closable,
89 | this.closeIcon,
90 | this.extra,
91 | this.footer,
92 | this.height,
93 | required this.keyboard,
94 | required this.mask,
95 | required this.maskClosable,
96 | required this.placement,
97 | required this.size,
98 | this.title,
99 | this.width,
100 | required this.onClose,
101 | }) : super(key: key);
102 |
103 | final Widget? child;
104 | final bool closable;
105 | final Widget? closeIcon;
106 | final Widget? extra;
107 | final Widget? footer;
108 | final double? height;
109 | final bool keyboard;
110 | final bool mask;
111 | final bool maskClosable;
112 | final Placement placement;
113 | final Size size;
114 | final Widget? title;
115 | final double? width;
116 | final void Function() onClose;
117 |
118 | @override
119 | State<_Drawer> createState() => __DrawerState();
120 | }
121 |
122 | class __DrawerState extends State<_Drawer> {
123 | @override
124 | Widget build(BuildContext context) {
125 | Axis direction = Axis.horizontal;
126 | if ([Placement.top, Placement.bottom].contains(widget.placement)) {
127 | direction = Axis.vertical;
128 | }
129 |
130 | double width = widget.width ?? (Size.large == widget.size ? 736 : 378);
131 | double height = widget.height ?? (Size.large == widget.size ? 736 : 378);
132 | if ([Placement.bottom, Placement.top].contains(widget.placement)) {
133 | width = double.infinity;
134 | }
135 | if ([Placement.left, Placement.right].contains(widget.placement)) {
136 | height = double.infinity;
137 | }
138 |
139 | Widget mask = Expanded(
140 | child: GestureDetector(
141 | onTap: _handleClose,
142 | child: Container(
143 | color: Colors.black.withOpacity(0.5),
144 | ),
145 | ),
146 | );
147 |
148 | Widget closeIcon = MouseRegion(
149 | cursor: SystemMouseCursors.click,
150 | child: GestureDetector(
151 | onTap: _handleClose,
152 | child: widget.closeIcon ??
153 | const Icon(Icons.close, color: Colors.gray_7, size: 16),
154 | ),
155 | );
156 |
157 | Widget title = Container(
158 | decoration: const BoxDecoration(
159 | border: Border(bottom: BorderSide(color: Colors.gray_3)),
160 | ),
161 | padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
162 | child: Row(
163 | children: [
164 | widget.closable ? closeIcon : const SizedBox(),
165 | SizedBox(width: widget.closable ? 12 : null),
166 | Expanded(
167 | child: DefaultTextStyle.merge(
168 | child: widget.title ?? const SizedBox(),
169 | style: const TextStyle(fontWeight: FontWeight.w500),
170 | ),
171 | ),
172 | widget.extra ?? const SizedBox(),
173 | ],
174 | ),
175 | );
176 |
177 | Widget child = Container(
178 | color: Colors.white,
179 | height: height,
180 | width: width,
181 | child: Column(
182 | crossAxisAlignment: CrossAxisAlignment.start,
183 | children: [
184 | widget.closable || widget.title != null || widget.extra != null
185 | ? title
186 | : const SizedBox(),
187 | Expanded(
188 | child: Container(
189 | padding: const EdgeInsets.all(24),
190 | child: widget.child,
191 | ),
192 | ),
193 | widget.footer ?? const SizedBox(),
194 | ],
195 | ),
196 | );
197 |
198 | return Material(
199 | color: const Color.fromARGB(0, 255, 255, 255),
200 | child: Flex(
201 | direction: direction,
202 | children: [Placement.bottom, Placement.right].contains(widget.placement)
203 | ? [mask, child]
204 | : [child, mask],
205 | ),
206 | );
207 | }
208 |
209 | void _handleClose() {
210 | if (widget.maskClosable) {
211 | widget.onClose.call();
212 | }
213 | }
214 | }
215 |
--------------------------------------------------------------------------------
/lib/src/widget/dropdown.dart:
--------------------------------------------------------------------------------
1 | import 'package:ant_design_flutter/src/enum/size.dart';
2 | import 'package:ant_design_flutter/src/widget/button.dart';
3 | import 'package:flutter/widgets.dart';
4 |
5 | class Dropdown extends StatefulWidget {
6 | const Dropdown({
7 | Key? key,
8 | required this.child,
9 | this.arrow,
10 | this.disabled,
11 | this.getPopupContainer,
12 | required this.overlay,
13 | this.placement = Alignment.bottomLeft,
14 | this.trigger = const [DropdownTrigger.hover],
15 | required this.visible,
16 | this.onVisibleChange,
17 | }) : super(key: key);
18 |
19 | final Widget child;
20 | final DropdownArrow? arrow;
21 | final bool? disabled;
22 | final Widget Function(Widget triggerNode)? getPopupContainer;
23 | final Widget overlay;
24 | final Alignment placement;
25 | final List trigger;
26 | final bool visible;
27 | final void Function(bool visible)? onVisibleChange;
28 |
29 | @override
30 | State createState() => _DropdownState();
31 | }
32 |
33 | class _DropdownState extends State {
34 | @override
35 | Widget build(BuildContext context) {
36 | return Container();
37 | }
38 | }
39 |
40 | class DropdownArrow {
41 | DropdownArrow({required this.pointAtCenter});
42 | bool pointAtCenter;
43 | }
44 |
45 | enum DropdownTrigger { click, hover, contextMenu }
46 |
47 | class DropdownButton extends StatefulWidget {
48 | const DropdownButton(
49 | {Key? key,
50 | required this.child,
51 | this.buttonsBuilder,
52 | this.loading = false,
53 | this.icon,
54 | required this.overlay,
55 | this.placement = Alignment.bottomLeft,
56 | this.size = Size.middle,
57 | this.trigger = const [DropdownTrigger.hover],
58 | this.type = ButtonType.normal,
59 | required this.visible,
60 | this.onClick,
61 | this.onVisibleChange})
62 | : super(key: key);
63 |
64 | final Widget child;
65 | final List Function()? buttonsBuilder;
66 | final bool loading;
67 | final Widget? icon;
68 | final Widget overlay;
69 | final Alignment placement;
70 | final Size size;
71 | final List trigger;
72 | final ButtonType type;
73 | final bool visible;
74 | final void Function()? onClick;
75 | final void Function(bool visible)? onVisibleChange;
76 |
77 | @override
78 | State createState() => _DropdownButtonState();
79 | }
80 |
81 | class _DropdownButtonState extends State {
82 | @override
83 | Widget build(BuildContext context) {
84 | return Container();
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/lib/src/widget/empty.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/empty.dart
--------------------------------------------------------------------------------
/lib/src/widget/flex.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/flex.dart
--------------------------------------------------------------------------------
/lib/src/widget/float_button.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/float_button.dart
--------------------------------------------------------------------------------
/lib/src/widget/form.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/form.dart
--------------------------------------------------------------------------------
/lib/src/widget/grid.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/grid.dart
--------------------------------------------------------------------------------
/lib/src/widget/icon.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 |
3 | import 'package:flutter/widgets.dart' as widgets;
4 |
5 | class Icon extends widgets.StatefulWidget {
6 | const Icon(
7 | this.icon, {
8 | widgets.Key? key,
9 | this.color,
10 | this.rotate,
11 | this.size,
12 | this.spin = false,
13 | }) : super(key: key);
14 |
15 | final widgets.Color? color;
16 | final widgets.IconData icon;
17 | final double? rotate;
18 | final double? size;
19 | final bool spin;
20 |
21 | @override
22 | widgets.State createState() => _IconState();
23 | }
24 |
25 | class _IconState extends widgets.State
26 | with widgets.SingleTickerProviderStateMixin {
27 | late widgets.AnimationController animatedController;
28 |
29 | @override
30 | void initState() {
31 | super.initState();
32 | animatedController = widgets.AnimationController(
33 | vsync: this,
34 | duration: const Duration(seconds: 1),
35 | )..repeat();
36 | }
37 |
38 | @override
39 | void dispose() {
40 | animatedController.dispose();
41 | super.dispose();
42 | }
43 |
44 | @override
45 | widgets.Widget build(widgets.BuildContext context) {
46 | var icon = widgets.Icon(
47 | widget.icon,
48 | color: widget.color,
49 | size: widget.size,
50 | );
51 |
52 | var rotate = widget.rotate != null ? widget.rotate! * pi / 180 : 0.0;
53 | var rotateIcon = widgets.Transform.rotate(angle: rotate, child: icon);
54 |
55 | return widget.spin
56 | ? widgets.RotationTransition(
57 | turns: animatedController,
58 | child: widget.rotate != null ? rotateIcon : icon,
59 | )
60 | : widget.rotate != null
61 | ? rotateIcon
62 | : icon;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/lib/src/widget/image.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/widgets.dart' as material;
2 |
3 | class Image extends material.StatefulWidget {
4 | const Image({
5 | material.Key? key,
6 | this.alt,
7 | this.fallback,
8 | this.height,
9 | this.onError,
10 | this.placeholder,
11 | this.preview = false,
12 | required this.src,
13 | this.width,
14 | }) : super(key: key);
15 |
16 | final String? alt;
17 | final String? fallback;
18 | final double? height;
19 | final void Function()? onError;
20 | final material.Widget? placeholder;
21 | final bool preview;
22 | final String src;
23 | final double? width;
24 |
25 | @override
26 | material.State createState() => _ImageState();
27 | }
28 |
29 | class _ImageState extends material.State {
30 | @override
31 | material.Widget build(material.BuildContext context) {
32 | return material.Image(
33 | height: widget.height,
34 | image: widget.src.contains('http')
35 | ? material.NetworkImage(widget.src)
36 | : material.AssetImage(widget.src) as material.ImageProvider,
37 | semanticLabel: widget.alt,
38 | width: widget.width,
39 | );
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/src/widget/input.dart:
--------------------------------------------------------------------------------
1 | import 'package:ant_design_flutter/src/enum/size.dart';
2 | import 'package:ant_design_flutter/src/enum/status.dart';
3 | import 'package:ant_design_flutter/src/style/color.dart';
4 | import 'package:flutter/material.dart'
5 | show InputBorder, InputDecoration, TextField;
6 | import 'package:flutter/widgets.dart';
7 |
8 | class Input extends StatefulWidget {
9 | const Input({
10 | Key? key,
11 | this.addonAfter,
12 | this.addonBefore,
13 | this.allowClear = false,
14 | this.bordered = true,
15 | this.disabled = false,
16 | this.maxLength,
17 | this.onChange,
18 | this.onPressEnter,
19 | this.showCount = false,
20 | this.status,
21 | this.placeholder,
22 | this.prefix,
23 | this.size = Size.middle,
24 | this.suffix,
25 | this.type = InputType.text,
26 | this.value,
27 | }) : super(key: key);
28 |
29 | final Widget? addonAfter;
30 | final Widget? addonBefore;
31 | final bool allowClear;
32 | final bool bordered;
33 | final bool disabled;
34 | final int? maxLength;
35 | final void Function()? onChange;
36 | final void Function()? onPressEnter;
37 | final bool showCount;
38 | final Status? status;
39 | final String? placeholder;
40 | final Widget? prefix;
41 | final Size size;
42 | final Widget? suffix;
43 | final InputType type;
44 | final String? value;
45 |
46 | @override
47 | State createState() => _InputState();
48 | }
49 |
50 | class _InputState extends State {
51 | static const height = {
52 | Size.small: 24.0,
53 | Size.middle: 32.0,
54 | Size.large: 40.0,
55 | };
56 |
57 | bool actived = false;
58 | FocusNode focusNode = FocusNode();
59 | bool hovered = false;
60 |
61 | @override
62 | void initState() {
63 | super.initState();
64 | focusNode.addListener(_focusNodeListener);
65 | }
66 |
67 | @override
68 | void dispose() {
69 | super.dispose();
70 | focusNode.removeListener(_focusNodeListener);
71 | focusNode.dispose();
72 | }
73 |
74 | @override
75 | Widget build(BuildContext context) {
76 | return MouseRegion(
77 | cursor: SystemMouseCursors.text,
78 | onEnter: (_) => setState(() {
79 | hovered = true;
80 | }),
81 | onExit: (_) => setState(() {
82 | hovered = false;
83 | }),
84 | child: GestureDetector(
85 | child: Container(
86 | decoration: BoxDecoration(
87 | border: Border.all(
88 | color: actived || hovered ? Colors.blue_6 : Colors.gray_5,
89 | ),
90 | borderRadius: BorderRadius.circular(2),
91 | ),
92 | height: height[widget.size],
93 | padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
94 | child: Center(
95 | child: TextField(
96 | decoration: InputDecoration(
97 | border: InputBorder.none,
98 | hintText: widget.placeholder,
99 | hintStyle: const TextStyle(color: Colors.gray_5, fontSize: 14),
100 | isCollapsed: true,
101 | ),
102 | focusNode: focusNode,
103 | style: const TextStyle(fontSize: 14),
104 | ),
105 | ),
106 | ),
107 | onTap: () => FocusScope.of(context).requestFocus(focusNode),
108 | ),
109 | );
110 | }
111 |
112 | void _focusNodeListener() {
113 | if (focusNode.hasFocus) {
114 | setState(() {
115 | actived = true;
116 | });
117 | } else {
118 | setState(() {
119 | actived = false;
120 | });
121 | }
122 | }
123 | }
124 |
125 | enum InputType { text }
126 |
127 | class InputController extends ChangeNotifier {
128 | String? value;
129 | }
130 |
--------------------------------------------------------------------------------
/lib/src/widget/input_number.dart:
--------------------------------------------------------------------------------
1 | import 'package:ant_design_flutter/src/enum/size.dart';
2 | import 'package:ant_design_flutter/src/enum/status.dart';
3 | import 'package:ant_design_flutter/src/style/color.dart';
4 | import 'package:ant_design_flutter/src/style/icon.dart';
5 | import 'package:flutter/material.dart'
6 | show InputBorder, InputDecoration, TextField;
7 | import 'package:flutter/widgets.dart';
8 |
9 | class InputNumber extends StatefulWidget {
10 | const InputNumber({
11 | Key? key,
12 | this.addonAfter,
13 | this.addonBefore,
14 | this.autoFocus = false,
15 | this.bordered = true,
16 | this.controller,
17 | this.controls = true,
18 | this.decimalSeparator,
19 | this.disabled = false,
20 | this.formatter,
21 | this.keyboard = true,
22 | this.max = double.maxFinite,
23 | this.min = double.minPositive,
24 | this.onChange,
25 | this.onPressEnter,
26 | this.onStep,
27 | this.parser,
28 | this.placeholder,
29 | this.precision,
30 | this.prefix,
31 | this.readOnly = false,
32 | this.stringMode = false,
33 | this.status,
34 | this.size = Size.middle,
35 | this.step = 1,
36 | }) : super(key: key);
37 |
38 | final Widget? addonAfter;
39 | final Widget? addonBefore;
40 | final bool autoFocus;
41 | final bool bordered;
42 | final InputNumberController? controller;
43 | final bool controls;
44 | final String? decimalSeparator;
45 | final bool disabled;
46 | final String Function()? formatter;
47 | final bool keyboard;
48 | final double max;
49 | final double min;
50 | final void Function()? onChange;
51 | final void Function()? onPressEnter;
52 | final void Function()? onStep;
53 | final double Function()? parser;
54 | final String? placeholder;
55 | final double? precision;
56 | final Widget? prefix;
57 | final bool readOnly;
58 | final bool stringMode;
59 | final Status? status;
60 | final Size size;
61 | final double step;
62 |
63 | @override
64 | State createState() => _InputNumberState();
65 | }
66 |
67 | class _InputNumberState extends State {
68 | static const height = {
69 | Size.small: 24.0,
70 | Size.middle: 32.0,
71 | Size.large: 40.0,
72 | };
73 |
74 | bool actived = false;
75 | String? clickedIcon;
76 | FocusNode focusNode = FocusNode();
77 | bool hovered = false;
78 | String? hoveredIcon;
79 | TextEditingController textEditingController = TextEditingController();
80 |
81 | @override
82 | void initState() {
83 | super.initState();
84 | focusNode.addListener(_focusNodeListener);
85 | textEditingController.text = widget.controller?.value?.toString() ?? '';
86 | textEditingController.addListener(() {
87 | widget.controller?.value = double.parse(textEditingController.text);
88 | });
89 | }
90 |
91 | @override
92 | void dispose() {
93 | super.dispose();
94 | focusNode.removeListener(_focusNodeListener);
95 | focusNode.dispose();
96 | textEditingController.dispose();
97 | }
98 |
99 | @override
100 | Widget build(BuildContext context) {
101 | return MouseRegion(
102 | cursor: SystemMouseCursors.text,
103 | onEnter: (_) => setState(() {
104 | hovered = true;
105 | }),
106 | onExit: (_) => setState(() {
107 | hovered = false;
108 | }),
109 | child: GestureDetector(
110 | child: Container(
111 | decoration: BoxDecoration(
112 | border: Border.all(
113 | color: actived || hovered ? Colors.blue_6 : Colors.gray_5,
114 | ),
115 | borderRadius: BorderRadius.circular(2),
116 | ),
117 | height: height[widget.size],
118 | child: Row(
119 | children: [
120 | Expanded(
121 | child: Container(
122 | padding: const EdgeInsets.symmetric(
123 | horizontal: 12,
124 | vertical: 4,
125 | ),
126 | child: TextField(
127 | controller: textEditingController,
128 | decoration: InputDecoration(
129 | border: InputBorder.none,
130 | hintText: widget.placeholder,
131 | hintStyle:
132 | const TextStyle(color: Colors.gray_5, fontSize: 14),
133 | isCollapsed: true,
134 | ),
135 | focusNode: focusNode,
136 | style: const TextStyle(fontSize: 14),
137 | ),
138 | ),
139 | ),
140 | Visibility(
141 | visible: hovered,
142 | child: Container(
143 | decoration: const BoxDecoration(
144 | border: Border(left: BorderSide(color: Colors.gray_5)),
145 | ),
146 | height: 30,
147 | width: 22,
148 | child: Column(
149 | children: [
150 | MouseRegion(
151 | cursor: SystemMouseCursors.click,
152 | onEnter: (_) => setState(() {
153 | hoveredIcon = 'up';
154 | }),
155 | onExit: (_) => setState(() {
156 | hoveredIcon = null;
157 | }),
158 | child: GestureDetector(
159 | child: Container(
160 | decoration: BoxDecoration(
161 | border: const Border(
162 | bottom: BorderSide(color: Colors.gray_5),
163 | ),
164 | color: clickedIcon != null && clickedIcon == 'up'
165 | ? Colors.gray_3
166 | : null,
167 | ),
168 | height: hoveredIcon == null
169 | ? 15
170 | : hoveredIcon == 'up'
171 | ? 18
172 | : 12,
173 | width: 22,
174 | child: Icon(
175 | Icons.chevron_up,
176 | color: hoveredIcon != null && hoveredIcon == 'up'
177 | ? Colors.gray_6
178 | : Colors.gray_5,
179 | size: 12,
180 | ),
181 | ),
182 | onTapDown: (_) {
183 | setState(() {
184 | clickedIcon = 'up';
185 | });
186 | double current =
187 | double.parse(textEditingController.text);
188 | if (current + widget.step <= widget.max) {
189 | textEditingController.text =
190 | (current + widget.step).toString();
191 | widget.controller?.value = current + widget.step;
192 | }
193 | },
194 | onTapUp: (_) {
195 | setState(() {
196 | clickedIcon = null;
197 | });
198 | },
199 | ),
200 | ),
201 | MouseRegion(
202 | cursor: SystemMouseCursors.click,
203 | onEnter: (_) => setState(() {
204 | hoveredIcon = 'down';
205 | }),
206 | onExit: (_) => setState(() {
207 | hoveredIcon = null;
208 | }),
209 | child: GestureDetector(
210 | child: Container(
211 | decoration: BoxDecoration(
212 | color:
213 | clickedIcon != null && clickedIcon == 'down'
214 | ? Colors.gray_3
215 | : null,
216 | ),
217 | height: hoveredIcon == null
218 | ? 15
219 | : hoveredIcon == 'down'
220 | ? 18
221 | : 12,
222 | width: 22,
223 | child: Icon(
224 | Icons.chevron_down,
225 | color:
226 | hoveredIcon != null && hoveredIcon == 'down'
227 | ? Colors.gray_6
228 | : Colors.gray_5,
229 | size: 12,
230 | ),
231 | ),
232 | onTapDown: (_) {
233 | setState(() {
234 | clickedIcon = 'down';
235 | });
236 | double current =
237 | double.parse(textEditingController.text);
238 | if (current - widget.step >= widget.min) {
239 | textEditingController.text =
240 | (current - widget.step).toString();
241 | widget.controller?.value = current - widget.step;
242 | }
243 | },
244 | onTapUp: (_) {
245 | setState(() {
246 | clickedIcon = null;
247 | });
248 | },
249 | ),
250 | ),
251 | ],
252 | ),
253 | ),
254 | )
255 | ],
256 | ),
257 | ),
258 | onTap: () => FocusScope.of(context).requestFocus(focusNode),
259 | ),
260 | );
261 | }
262 |
263 | void _focusNodeListener() {
264 | if (focusNode.hasFocus) {
265 | setState(() {
266 | actived = true;
267 | });
268 | } else {
269 | textEditingController.text =
270 | double.parse(textEditingController.text).toString();
271 | setState(() {
272 | actived = false;
273 | });
274 | }
275 | }
276 | }
277 |
278 | class InputNumberController {
279 | InputNumberController.fromValue(this.value);
280 |
281 | double? value;
282 | }
283 |
--------------------------------------------------------------------------------
/lib/src/widget/layout.dart:
--------------------------------------------------------------------------------
1 | import 'package:ant_design_flutter/src/enum/theme.dart';
2 | import 'package:flutter/widgets.dart';
3 |
4 | class Layout extends StatelessWidget {
5 | const Layout({Key? key, required this.child, this.hasSider})
6 | : super(key: key);
7 |
8 | final Widget child;
9 | final bool? hasSider;
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return Container();
14 | }
15 | }
16 |
17 | class Sider extends StatefulWidget {
18 | const Sider({
19 | Key? key,
20 | required this.child,
21 | this.breakpoint,
22 | this.collapsed,
23 | this.collapsedWidth = 80,
24 | this.collapsible = false,
25 | this.defaultCollapsed = false,
26 | this.reverseArrow = false,
27 | this.theme = Theme.dark,
28 | this.trigger,
29 | this.width = 200,
30 | this.onBreakpoint,
31 | this.onCollapse,
32 | }) : super(key: key);
33 |
34 | final Widget child;
35 | final SiderBreakpoint? breakpoint;
36 | final bool? collapsed;
37 | final double collapsedWidth;
38 | final bool collapsible;
39 | final bool defaultCollapsed;
40 | final bool reverseArrow;
41 | final Theme theme;
42 | final Widget? trigger;
43 | final double width;
44 | final void Function()? onBreakpoint;
45 | final void Function(bool collapsed)? onCollapse;
46 |
47 | @override
48 | State createState() => _SiderState();
49 | }
50 |
51 | class _SiderState extends State {
52 | @override
53 | Widget build(BuildContext context) {
54 | return Container();
55 | }
56 | }
57 |
58 | class SiderBreakpoint {
59 | SiderBreakpoint({
60 | this.xs = 480,
61 | this.sm = 576,
62 | this.md = 768,
63 | this.lg = 992,
64 | this.xl = 1200,
65 | this.xxl = 1600,
66 | });
67 |
68 | double xs;
69 | double sm;
70 | double md;
71 | double lg;
72 | double xl;
73 | double xxl;
74 | }
75 |
76 | class Header extends StatelessWidget {
77 | const Header({Key? key, required this.child}) : super(key: key);
78 |
79 | final Widget child;
80 |
81 | @override
82 | Widget build(BuildContext context) {
83 | return Container();
84 | }
85 | }
86 |
87 | class Content extends StatelessWidget {
88 | const Content({Key? key, required this.child}) : super(key: key);
89 |
90 | final Widget child;
91 |
92 | @override
93 | Widget build(BuildContext context) {
94 | return Container();
95 | }
96 | }
97 |
98 | class Footer extends StatelessWidget {
99 | const Footer({Key? key, required this.child}) : super(key: key);
100 |
101 | final Widget child;
102 |
103 | @override
104 | Widget build(BuildContext context) {
105 | return Container();
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/lib/src/widget/list.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/list.dart
--------------------------------------------------------------------------------
/lib/src/widget/mentions.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/mentions.dart
--------------------------------------------------------------------------------
/lib/src/widget/menu.dart:
--------------------------------------------------------------------------------
1 | import 'package:ant_design_flutter/src/style/color.dart';
2 | import 'package:ant_design_flutter/src/enum/theme.dart';
3 | import 'package:flutter/widgets.dart';
4 |
5 | class Menu extends StatefulWidget {
6 | const Menu({
7 | Key? key,
8 | required this.children,
9 | this.defaultOpenKeys,
10 | this.defaultSelectedKeys,
11 | this.expandIcon,
12 | this.forceSubMenuRender = false,
13 | this.inlineCollapsed,
14 | this.inlineIndent = 24,
15 | this.mode = MenuMode.vertical,
16 | this.multiple = false,
17 | this.openKeys,
18 | this.overflowIndicator,
19 | this.selectable = true,
20 | this.selectedKeys,
21 | this.subMenuCloseDelay = 100,
22 | this.subMenuOpenDelay = 0,
23 | this.theme = Theme.light,
24 | this.triggerSubMenuAction = SubMenuAction.hover,
25 | this.onClick,
26 | this.onDeselect,
27 | this.onOpenChange,
28 | this.onSelect,
29 | }) : super(key: key);
30 |
31 | final List children;
32 | final List? defaultOpenKeys;
33 | final List? defaultSelectedKeys;
34 | final Widget? expandIcon;
35 | final bool forceSubMenuRender;
36 | final bool? inlineCollapsed;
37 | final double inlineIndent;
38 | final MenuMode mode;
39 | final bool multiple;
40 | final List? openKeys;
41 | final Widget? overflowIndicator;
42 | final bool selectable;
43 | final List? selectedKeys;
44 | final double subMenuCloseDelay;
45 | final double subMenuOpenDelay;
46 | final Theme theme;
47 | final SubMenuAction triggerSubMenuAction;
48 | final void Function(MenuItem item, String key)? onClick;
49 | final void Function(
50 | MenuItem item,
51 | String key,
52 | List selectedKeys,
53 | )? onDeselect;
54 | final void Function(List openKeys)? onOpenChange;
55 | final void Function(
56 | MenuItem item,
57 | String key,
58 | List selectedKeys,
59 | )? onSelect;
60 |
61 | @override
62 | State createState() => _MenuState();
63 | }
64 |
65 | class _MenuState extends State {
66 | late String current;
67 |
68 | @override
69 | void initState() {
70 | super.initState();
71 | setState(() {
72 | current = widget.selectedKeys?.first ?? '';
73 | });
74 | }
75 |
76 | @override
77 | Widget build(BuildContext context) {
78 | return _MenuInhertedWidget(
79 | current: current,
80 | indent: widget.inlineIndent,
81 | inlineCollapsed: widget.inlineCollapsed ?? false,
82 | mode: widget.mode,
83 | theme: widget.theme,
84 | updateCurrent: _updateCurrent,
85 | onClick: widget.onClick,
86 | onSelect: widget.onSelect,
87 | child: Container(
88 | decoration: BoxDecoration(
89 | border: Border(
90 | bottom: widget.mode == MenuMode.horizontal
91 | ? const BorderSide(color: Colors.gray_4)
92 | : BorderSide.none,
93 | right: widget.mode != MenuMode.horizontal
94 | ? const BorderSide(color: Colors.gray_4)
95 | : BorderSide.none,
96 | ),
97 | color: widget.theme == Theme.dark ? Colors.black : Colors.white,
98 | ),
99 | child: Flex(
100 | crossAxisAlignment: CrossAxisAlignment.start,
101 | direction: widget.mode == MenuMode.horizontal
102 | ? Axis.horizontal
103 | : Axis.vertical,
104 | children: _buildChildren(),
105 | ),
106 | ),
107 | );
108 | }
109 |
110 | List _buildChildren() {
111 | var children = [];
112 | for (var child in widget.children) {
113 | if (child is MenuItem) {
114 | children.add(child);
115 | } else if (child is MenuDivider) {
116 | children.add(child);
117 | } else if (child is MenuItemGroup) {
118 | children.add(child);
119 | }
120 | }
121 | return children;
122 | }
123 |
124 | void _updateCurrent(String name) {
125 | setState(() {
126 | current = name;
127 | });
128 | }
129 | }
130 |
131 | enum MenuMode { vertical, horizontal, inline }
132 |
133 | enum SubMenuAction { hover, click }
134 |
135 | class MenuItem extends StatefulWidget {
136 | const MenuItem({
137 | Key? key,
138 | required this.child,
139 | this.danger = false,
140 | this.disabled = false,
141 | this.icon,
142 | required this.name,
143 | this.title,
144 | }) : super(key: key);
145 |
146 | final Widget child;
147 | final bool danger;
148 | final bool disabled;
149 | final Widget? icon;
150 | final String name;
151 | final String? title;
152 |
153 | @override
154 | State createState() => _MenuItemState();
155 | }
156 |
157 | class _MenuItemState extends State {
158 | bool hovered = false;
159 |
160 | @override
161 | Widget build(BuildContext context) {
162 | var current = _MenuInhertedWidget.of(context)!.current;
163 | var indent = _MenuInhertedWidget.of(context)!.indent;
164 | var inlineCollapsed = _MenuInhertedWidget.of(context)!.inlineCollapsed;
165 | var mode = _MenuInhertedWidget.of(context)!.mode;
166 | var theme = _MenuInhertedWidget.of(context)!.theme;
167 |
168 | return MouseRegion(
169 | cursor: SystemMouseCursors.click,
170 | onEnter: (_) => setState(() {
171 | hovered = true;
172 | }),
173 | onExit: (_) => setState(() {
174 | hovered = false;
175 | }),
176 | child: GestureDetector(
177 | onTap: _handleTap,
178 | child: Container(
179 | decoration: BoxDecoration(
180 | border: current == widget.name
181 | ? Border(
182 | bottom: MenuMode.horizontal == mode
183 | ? const BorderSide(color: Colors.blue_6, width: 2)
184 | : BorderSide.none,
185 | right: MenuMode.horizontal != mode
186 | ? const BorderSide(color: Colors.blue_6, width: 3)
187 | : BorderSide.none,
188 | )
189 | : null,
190 | color: Theme.light == theme
191 | ? widget.name == current
192 | ? Colors.blue_1
193 | : Colors.white
194 | : widget.name == current
195 | ? Colors.blue_6
196 | : Colors.black,
197 | ),
198 | padding: EdgeInsets.symmetric(horizontal: indent, vertical: 13),
199 | width: mode == MenuMode.horizontal
200 | ? null
201 | : inlineCollapsed
202 | ? 80
203 | : double.infinity,
204 | child: DefaultTextStyle.merge(
205 | child: widget.child,
206 | maxLines: 1,
207 | overflow: TextOverflow.clip,
208 | softWrap: true,
209 | style: TextStyle(
210 | color: Theme.light == theme
211 | ? hovered || widget.name == current
212 | ? Colors.blue_6
213 | : Colors.black
214 | : hovered || widget.name == current
215 | ? Colors.white
216 | : Colors.gray_4,
217 | fontSize: 14,
218 | ),
219 | ),
220 | ),
221 | ),
222 | );
223 | }
224 |
225 | void _handleTap() {
226 | var current = _MenuInhertedWidget.of(context)!.current;
227 | var onClick = _MenuInhertedWidget.of(context)!.onClick;
228 | var onSelect = _MenuInhertedWidget.of(context)!.onSelect;
229 | if (current != widget.name) {
230 | onClick?.call(widget, widget.name);
231 | onSelect?.call(widget, widget.name, [current]);
232 | }
233 | _MenuInhertedWidget.of(context)!.updateCurrent(widget.name);
234 | }
235 | }
236 |
237 | class SubMenu extends StatelessWidget {
238 | const SubMenu({
239 | Key? key,
240 | required this.children,
241 | this.disabled = false,
242 | this.icon,
243 | required this.name,
244 | required this.popupOffset,
245 | this.title,
246 | this.onTitleClick,
247 | this.theme = Theme.light,
248 | }) : super(key: key);
249 |
250 | final List children;
251 | final bool disabled;
252 | final Widget? icon;
253 | final String name;
254 | final Offset popupOffset;
255 | final Widget? title;
256 | final void Function(String name)? onTitleClick;
257 | final Theme theme;
258 |
259 | @override
260 | Widget build(BuildContext context) {
261 | return Container();
262 | }
263 | }
264 |
265 | class MenuItemGroup extends StatelessWidget {
266 | const MenuItemGroup({Key? key, required this.children, this.label})
267 | : super(key: key);
268 |
269 | final List children;
270 | final Widget? label;
271 |
272 | @override
273 | Widget build(BuildContext context) {
274 | var indent = _MenuInhertedWidget.of(context)!.indent;
275 |
276 | return Column(
277 | crossAxisAlignment: CrossAxisAlignment.start,
278 | children: [
279 | label != null
280 | ? Container(
281 | decoration: const BoxDecoration(
282 | border: Border(
283 | bottom: BorderSide(color: Colors.gray_4),
284 | ),
285 | ),
286 | margin: EdgeInsets.symmetric(horizontal: indent),
287 | padding: const EdgeInsets.symmetric(vertical: 13),
288 | width: double.infinity,
289 | child: DefaultTextStyle.merge(
290 | child: label!,
291 | style: const TextStyle(color: Colors.gray_7),
292 | ),
293 | )
294 | : const SizedBox(),
295 | Column(
296 | crossAxisAlignment: CrossAxisAlignment.start,
297 | children: children,
298 | ),
299 | ],
300 | );
301 | }
302 | }
303 |
304 | class MenuDivider extends StatelessWidget {
305 | const MenuDivider({Key? key, this.dashed = false}) : super(key: key);
306 |
307 | final bool dashed;
308 |
309 | @override
310 | Widget build(BuildContext context) {
311 | return Container();
312 | }
313 | }
314 |
315 | class _MenuInhertedWidget extends InheritedWidget {
316 | final String current;
317 | final double indent;
318 | final bool inlineCollapsed;
319 | final MenuMode mode;
320 | final void Function(MenuItem item, String name)? onClick;
321 | final void Function(
322 | MenuItem item,
323 | String name,
324 | List selectedKeys,
325 | )? onSelect;
326 | final Theme theme;
327 | final void Function(String name) updateCurrent;
328 |
329 | const _MenuInhertedWidget({
330 | required Widget child,
331 | required this.current,
332 | required this.indent,
333 | required this.inlineCollapsed,
334 | required this.mode,
335 | required this.theme,
336 | required this.updateCurrent,
337 | this.onClick,
338 | this.onSelect,
339 | Key? key,
340 | }) : super(child: child, key: key);
341 |
342 | static _MenuInhertedWidget? of(BuildContext context) {
343 | return context.dependOnInheritedWidgetOfExactType<_MenuInhertedWidget>();
344 | }
345 |
346 | @override
347 | bool updateShouldNotify(_MenuInhertedWidget oldWidget) {
348 | return oldWidget.current != current;
349 | }
350 | }
351 |
--------------------------------------------------------------------------------
/lib/src/widget/message.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:ant_design_flutter/src/enum/status.dart';
4 | import 'package:ant_design_flutter/src/style/color.dart';
5 | import 'package:ant_design_flutter/src/style/icon.dart';
6 | import 'package:ant_design_flutter/src/widget/app.dart';
7 | import 'package:flutter/material.dart' show Material;
8 | import 'package:flutter/widgets.dart';
9 |
10 | class Message {
11 | static void success(
12 | BuildContext context, {
13 | required Widget content,
14 | Duration duration = const Duration(seconds: 3),
15 | Widget? icon,
16 | void Function()? onClick,
17 | void Function()? onClose,
18 | }) {
19 | _insertEntry(
20 | context,
21 | ValueKey(DateTime.now()),
22 | content,
23 | duration,
24 | icon,
25 | Status.success,
26 | onClick,
27 | onClose,
28 | );
29 | }
30 |
31 | static void error(
32 | BuildContext context, {
33 | required Widget content,
34 | Duration duration = const Duration(seconds: 3),
35 | Widget? icon,
36 | void Function()? onClick,
37 | void Function()? onClose,
38 | }) {
39 | _insertEntry(
40 | context,
41 | ValueKey(DateTime.now()),
42 | content,
43 | duration,
44 | icon,
45 | Status.error,
46 | onClick,
47 | onClose,
48 | );
49 | }
50 |
51 | static void info(
52 | BuildContext context, {
53 | required Widget content,
54 | Duration duration = const Duration(seconds: 3),
55 | Widget? icon,
56 | void Function()? onClick,
57 | void Function()? onClose,
58 | }) {
59 | _insertEntry(
60 | context,
61 | ValueKey(DateTime.now()),
62 | content,
63 | duration,
64 | icon,
65 | Status.info,
66 | onClick,
67 | onClose,
68 | );
69 | }
70 |
71 | static void warning(
72 | BuildContext context, {
73 | required Widget content,
74 | Duration duration = const Duration(seconds: 3),
75 | Widget? icon,
76 | void Function()? onClick,
77 | void Function()? onClose,
78 | }) {
79 | _insertEntry(
80 | context,
81 | ValueKey(DateTime.now()),
82 | content,
83 | duration,
84 | icon,
85 | Status.warning,
86 | onClick,
87 | onClose,
88 | );
89 | }
90 |
91 | static void _insertEntry(
92 | BuildContext context,
93 | ValueKey key,
94 | Widget content,
95 | Duration duration,
96 | Widget? icon,
97 | Status status,
98 | void Function()? onClick,
99 | void Function()? onClose,
100 | ) {
101 | OverlayEntry entry = OverlayEntry(
102 | builder: (_) =>
103 | _Message(key: key, content: content, icon: icon, status: status),
104 | );
105 | Overlay.of(context).insert(entry);
106 | var tops = GlobalQuery.of(context)?.tops;
107 | var top =
108 | tops != null && tops.isNotEmpty ? tops.length * 56.0 + 32.0 : 32.0;
109 | GlobalQuery.of(context)?.insert(key, top);
110 | Timer(duration, () {
111 | entry.remove();
112 | GlobalQuery.of(context)?.remove(key);
113 | });
114 | }
115 | }
116 |
117 | class _Message extends StatelessWidget {
118 | const _Message({
119 | Key? key,
120 | required this.content,
121 | this.icon,
122 | required this.status,
123 | }) : super(key: key);
124 |
125 | final Widget content;
126 | final Widget? icon;
127 | final Status status;
128 |
129 | @override
130 | Widget build(BuildContext context) {
131 | Map icons = {
132 | Status.success: Icons.success,
133 | Status.error: Icons.error,
134 | Status.info: Icons.info,
135 | Status.warning: Icons.warning
136 | };
137 | Map colors = {
138 | Status.success: Colors.green_6,
139 | Status.error: Colors.red_6,
140 | Status.info: Colors.blue_6,
141 | Status.warning: Colors.orange_6
142 | };
143 | Widget realIcon = IconTheme.merge(
144 | data: IconThemeData(color: colors[status], size: 16),
145 | child: icon ?? Icon(icons[status]),
146 | );
147 |
148 | Map? tops = GlobalQuery.of(context)?.tops;
149 |
150 | return Positioned(
151 | top: tops?[key] ?? 32,
152 | child: Container(
153 | alignment: Alignment.center,
154 | width: MediaQuery.of(context).size.width,
155 | child: Material(
156 | borderRadius: BorderRadius.circular(2),
157 | color: Colors.white,
158 | elevation: 8,
159 | shadowColor: Colors.gray_1,
160 | child: Container(
161 | padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
162 | child: Row(
163 | mainAxisSize: MainAxisSize.min,
164 | children: [realIcon, const SizedBox(width: 8), content],
165 | ),
166 | ),
167 | ),
168 | ),
169 | );
170 | }
171 | }
172 |
--------------------------------------------------------------------------------
/lib/src/widget/modal.dart:
--------------------------------------------------------------------------------
1 | import 'package:ant_design_flutter/src/style/color.dart';
2 | import 'package:ant_design_flutter/src/style/icon.dart';
3 | import 'package:ant_design_flutter/src/widget/button.dart';
4 | import 'package:flutter/material.dart' show Material, showDialog;
5 | import 'package:flutter/widgets.dart';
6 |
7 | class Modal {
8 | Modal(
9 | BuildContext context, {
10 | void Function()? afterClose,
11 | String cancelText = '取消',
12 | bool centered = false,
13 | bool closable = false,
14 | Widget? closeIcon,
15 | required Widget content,
16 | Widget? icon,
17 | bool keyboard = true,
18 | bool mask = true,
19 | bool maskClosable = false,
20 | String okText = '确定',
21 | ButtonType okType = ButtonType.primary,
22 | required Widget title,
23 | double width = 520,
24 | void Function()? onCancel,
25 | void Function()? onOk,
26 | }) {
27 | showDialog(
28 | context: context,
29 | builder: (_) => _Modal(
30 | afterClose: afterClose,
31 | cancelText: cancelText,
32 | centered: centered,
33 | closable: closable,
34 | closeIcon: closeIcon,
35 | content: content,
36 | icon: icon,
37 | keyboard: keyboard,
38 | mask: mask,
39 | maskClosable: maskClosable,
40 | okText: okText,
41 | okType: okType,
42 | title: title,
43 | width: width,
44 | onCancel: onCancel,
45 | onOk: onOk,
46 | ),
47 | );
48 | }
49 |
50 | static void success(
51 | BuildContext context, {
52 | void Function()? afterClose,
53 | String cancelText = '取消',
54 | bool centered = false,
55 | bool closable = false,
56 | Widget? closeIcon,
57 | required Widget content,
58 | Widget? icon,
59 | bool keyboard = true,
60 | bool mask = true,
61 | bool maskClosable = false,
62 | String okText = '确定',
63 | ButtonType okType = ButtonType.primary,
64 | required Widget title,
65 | double width = 416,
66 | void Function()? onCancel,
67 | void Function()? onOk,
68 | }) {
69 | showDialog(
70 | context: context,
71 | builder: (_) => _Modal(
72 | cancelText: cancelText,
73 | centered: centered,
74 | closable: closable,
75 | content: content,
76 | keyboard: keyboard,
77 | mask: mask,
78 | maskClosable: maskClosable,
79 | okText: okText,
80 | okType: okType,
81 | title: title,
82 | width: width,
83 | ),
84 | );
85 | }
86 | }
87 |
88 | class _Modal extends StatelessWidget {
89 | const _Modal({
90 | Key? key,
91 | this.afterClose,
92 | required this.cancelText,
93 | required this.centered,
94 | required this.closable,
95 | this.closeIcon,
96 | required this.content,
97 | this.icon,
98 | required this.keyboard,
99 | required this.mask,
100 | required this.maskClosable,
101 | required this.okText,
102 | required this.okType,
103 | required this.title,
104 | required this.width,
105 | this.onCancel,
106 | this.onOk,
107 | }) : super(key: key);
108 |
109 | final void Function()? afterClose;
110 | final String cancelText;
111 | final bool centered;
112 | final bool closable;
113 | final Widget? closeIcon;
114 | final Widget content;
115 | final Widget? icon;
116 | final bool keyboard;
117 | final bool mask;
118 | final bool maskClosable;
119 | final String okText;
120 | final ButtonType okType;
121 | final Widget title;
122 | final double width;
123 | final void Function()? onCancel;
124 | final void Function()? onOk;
125 |
126 | @override
127 | Widget build(BuildContext context) {
128 | Widget header = Container(
129 | decoration: const BoxDecoration(
130 | border: Border(bottom: BorderSide(color: Colors.gray_4)),
131 | ),
132 | padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
133 | child: Row(
134 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
135 | children: [
136 | DefaultTextStyle.merge(
137 | child: title,
138 | style: const TextStyle(fontWeight: FontWeight.w500),
139 | ),
140 | MouseRegion(
141 | cursor: SystemMouseCursors.click,
142 | child: GestureDetector(
143 | child: closeIcon ??
144 | const Icon(Icons.close, color: Colors.gray_5, size: 16),
145 | onTap: () => _handleCancel(context),
146 | ),
147 | ),
148 | ],
149 | ),
150 | );
151 |
152 | Widget footer = Container(
153 | decoration: const BoxDecoration(
154 | border: Border(top: BorderSide(color: Colors.gray_4)),
155 | ),
156 | padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
157 | child: Row(
158 | mainAxisAlignment: MainAxisAlignment.end,
159 | children: [
160 | Button(
161 | child: Text(cancelText),
162 | onClick: () => _handleCancel(context),
163 | ),
164 | const SizedBox(width: 8),
165 | Button(
166 | type: okType,
167 | onClick: () => _handleOk(context),
168 | child: Text(okText),
169 | ),
170 | ],
171 | ),
172 | );
173 |
174 | return Align(
175 | alignment: Alignment.topCenter,
176 | child: Padding(
177 | padding: const EdgeInsets.only(top: 80),
178 | child: Material(
179 | borderRadius: BorderRadius.circular(2),
180 | child: SizedBox(
181 | width: width,
182 | child: Column(
183 | crossAxisAlignment: CrossAxisAlignment.start,
184 | mainAxisSize: MainAxisSize.min,
185 | children: [
186 | header,
187 | Padding(padding: const EdgeInsets.all(24), child: content),
188 | footer,
189 | ],
190 | ),
191 | ),
192 | ),
193 | ),
194 | );
195 | }
196 |
197 | void _handleCancel(BuildContext context) {
198 | onCancel?.call();
199 | Navigator.of(context).pop();
200 | afterClose?.call();
201 | }
202 |
203 | void _handleOk(BuildContext context) {
204 | onOk?.call();
205 | Navigator.of(context).pop();
206 | afterClose?.call();
207 | }
208 | }
209 |
--------------------------------------------------------------------------------
/lib/src/widget/nested_gesture_detector.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/gestures.dart';
2 | import 'package:flutter/widgets.dart';
3 |
4 | class NestedGestureDetector extends StatelessWidget {
5 | const NestedGestureDetector({Key? key, required this.child, this.onTap})
6 | : super(key: key);
7 |
8 | final Widget child;
9 | final void Function()? onTap;
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return RawGestureDetector(
14 | behavior: HitTestBehavior.opaque,
15 | gestures: {
16 | _AllowNestedGestureRecognizer:
17 | GestureRecognizerFactoryWithHandlers<_AllowNestedGestureRecognizer>(
18 | () => _AllowNestedGestureRecognizer(),
19 | (_AllowNestedGestureRecognizer recognizer) {
20 | recognizer.onTap = onTap;
21 | })
22 | },
23 | child: child,
24 | );
25 | }
26 | }
27 |
28 | class _AllowNestedGestureRecognizer extends TapGestureRecognizer {
29 | @override
30 | void rejectGesture(int pointer) {
31 | acceptGesture(pointer);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/lib/src/widget/notification.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:ant_design_flutter/src/enum/placement.dart';
4 | import 'package:ant_design_flutter/src/style/color.dart';
5 | import 'package:ant_design_flutter/src/style/icon.dart';
6 | import 'package:ant_design_flutter/src/widget/app.dart';
7 | import 'package:flutter/material.dart' show Material;
8 | import 'package:flutter/widgets.dart';
9 |
10 | class Notification {
11 | static void open(
12 | BuildContext context, {
13 | double bottom = 24,
14 | Widget? btn,
15 | Widget? closeIcon,
16 | required Widget description,
17 | Duration? duration = const Duration(milliseconds: 4500),
18 | Widget? icon,
19 | required Widget message,
20 | Placement placement = Placement.topRight,
21 | double top = 24,
22 | void Function()? onClick,
23 | void Function()? onClose,
24 | }) {
25 | var tops = GlobalQuery.of(context)?.notificationTops;
26 | var realTop = top;
27 | if (tops != null) {
28 | var heights = tops.values.toList();
29 | for (int i = 0; i < heights.length; i++) {
30 | realTop += heights[i] + 16;
31 | }
32 | }
33 | var key = GlobalKey();
34 | var entry = OverlayEntry(
35 | builder: (_) => _Notification(
36 | key: key,
37 | bottom: bottom,
38 | btn: btn,
39 | closeIcon: closeIcon,
40 | description: description,
41 | duration: duration,
42 | icon: icon,
43 | message: message,
44 | placement: placement,
45 | top: realTop,
46 | onClick: onClick,
47 | onClose: onClose,
48 | ),
49 | );
50 | Overlay.of(context).insert(entry);
51 | var height = key.currentContext?.size?.height ?? 120;
52 | GlobalQuery.of(context)?.insertNotification(key, height);
53 | if (duration != null) {
54 | Timer(duration, () {
55 | entry.remove();
56 | GlobalQuery.of(context)?.removeNotification(key);
57 | });
58 | }
59 | }
60 | }
61 |
62 | class _Notification extends StatelessWidget {
63 | const _Notification({
64 | Key? key,
65 | required this.bottom,
66 | this.btn,
67 | this.closeIcon,
68 | required this.description,
69 | this.duration,
70 | this.icon,
71 | required this.message,
72 | required this.placement,
73 | required this.top,
74 | this.onClick,
75 | this.onClose,
76 | }) : super(key: key);
77 |
78 | final double bottom;
79 | final Widget? btn;
80 | final Widget? closeIcon;
81 | final Widget description;
82 | final Duration? duration;
83 | final Widget? icon;
84 | final Widget message;
85 | final Placement placement;
86 | final double top;
87 | final void Function()? onClick;
88 | final void Function()? onClose;
89 |
90 | @override
91 | Widget build(BuildContext context) {
92 | Widget header = Row(
93 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
94 | children: [
95 | DefaultTextStyle.merge(
96 | child: message,
97 | style: const TextStyle(fontWeight: FontWeight.w500),
98 | ),
99 | MouseRegion(
100 | cursor: SystemMouseCursors.click,
101 | child: GestureDetector(
102 | child: closeIcon ??
103 | const Icon(Icons.close, color: Colors.gray_5, size: 16),
104 | onTap: () => _handleClose(context),
105 | ),
106 | ),
107 | ],
108 | );
109 |
110 | Widget footer = Align(
111 | alignment: Alignment.centerRight,
112 | child: Padding(
113 | padding: const EdgeInsets.only(top: 8.0),
114 | child: btn,
115 | ),
116 | );
117 |
118 | return Align(
119 | alignment: Alignment.topRight,
120 | child: Padding(
121 | padding: EdgeInsets.only(right: bottom, top: top),
122 | child: Material(
123 | borderRadius: BorderRadius.circular(2),
124 | color: Colors.white,
125 | elevation: 8,
126 | shadowColor: Colors.gray_1,
127 | child: Container(
128 | padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
129 | width: 384,
130 | child: Column(
131 | crossAxisAlignment: CrossAxisAlignment.start,
132 | mainAxisSize: MainAxisSize.min,
133 | children: [
134 | header,
135 | const SizedBox(height: 8),
136 | description,
137 | if (btn != null) footer,
138 | ],
139 | ),
140 | ),
141 | ),
142 | ),
143 | );
144 | }
145 |
146 | void _handleClose(BuildContext context) {
147 | Navigator.of(context).pop();
148 | onClose?.call();
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/lib/src/widget/page_header.dart:
--------------------------------------------------------------------------------
1 | import 'package:ant_design_flutter/src/style/color.dart';
2 | import 'package:ant_design_flutter/src/style/icon.dart';
3 | import 'package:flutter/widgets.dart';
4 |
5 | class PageHeader extends StatelessWidget {
6 | const PageHeader({
7 | Key? key,
8 | this.avatar,
9 | this.backIcon = const Icon(Icons.arrow_left),
10 | this.breadcrumb,
11 | this.breadcrumbBuilder,
12 | this.extra,
13 | this.footer,
14 | this.ghost = false,
15 | this.subtitle,
16 | this.tags,
17 | required this.title,
18 | this.onBack,
19 | }) : super(key: key);
20 |
21 | final Widget? avatar;
22 | final Widget? backIcon;
23 | final Widget? breadcrumb;
24 | final Widget Function()? breadcrumbBuilder;
25 | final Widget? extra;
26 | final Widget? footer;
27 | final bool ghost;
28 | final Widget? subtitle;
29 | final List? tags;
30 | final Widget title;
31 | final void Function()? onBack;
32 |
33 | @override
34 | Widget build(BuildContext context) {
35 | return Row(
36 | children: [
37 | backIcon != null
38 | ? Padding(
39 | padding: const EdgeInsets.symmetric(horizontal: 12),
40 | child: backIcon,
41 | )
42 | : const SizedBox(),
43 | Padding(
44 | padding: const EdgeInsets.only(right: 12.0),
45 | child: DefaultTextStyle.merge(
46 | child: title,
47 | style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w500),
48 | ),
49 | ),
50 | subtitle != null
51 | ? DefaultTextStyle.merge(
52 | child: subtitle!,
53 | style: const TextStyle(color: Colors.gray_6),
54 | )
55 | : const SizedBox(),
56 | ],
57 | );
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/lib/src/widget/pagination.dart:
--------------------------------------------------------------------------------
1 | import 'package:ant_design_flutter/src/enum/size.dart';
2 | import 'package:ant_design_flutter/src/style/color.dart';
3 | import 'package:ant_design_flutter/src/style/icon.dart';
4 | import 'package:flutter/widgets.dart';
5 |
6 | class Pagination extends StatefulWidget {
7 | const Pagination({
8 | Key? key,
9 | this.controller,
10 | this.current,
11 | this.defaultCurrent = 1,
12 | this.defaultPageSize = 10,
13 | this.disabled,
14 | this.hideOnSinglePage = false,
15 | this.itemBuilder,
16 | this.pageSize = 10,
17 | this.pageSizeOptions = const [10, 20, 50, 100],
18 | this.responsive,
19 | this.showLessItems = false,
20 | this.showQuickJumper,
21 | this.showSizeChanger,
22 | this.showTitle = true,
23 | this.simple,
24 | this.size = Size.middle,
25 | this.total = 0,
26 | this.onChange,
27 | this.onShowSizeChange,
28 | }) : super(key: key);
29 |
30 | final PaginationController? controller;
31 | final int? current;
32 | final int defaultCurrent;
33 | final int defaultPageSize;
34 | final bool? disabled;
35 | final bool hideOnSinglePage;
36 | final Widget Function(int page)? itemBuilder;
37 | final int pageSize;
38 | final List pageSizeOptions;
39 | final bool? responsive;
40 | final bool showLessItems;
41 | final bool? showQuickJumper;
42 | final bool? showSizeChanger;
43 | final bool showTitle;
44 | final bool? simple;
45 | final Size size;
46 | final int total;
47 | final void Function(int page, int pageSize)? onChange;
48 | final void Function(int current, int size)? onShowSizeChange;
49 |
50 | @override
51 | State createState() => _PaginationState();
52 | }
53 |
54 | class _PaginationState extends State {
55 | int current = 0;
56 |
57 | @override
58 | void initState() {
59 | super.initState();
60 | if (widget.controller != null) {
61 | setState(() {
62 | current = widget.controller!.current;
63 | });
64 | }
65 | }
66 |
67 | @override
68 | Widget build(BuildContext context) {
69 | var totalPage = _calculateTotalPage();
70 |
71 | return _PaginationInhertedWidget(
72 | current: current,
73 | handleChange: _handleChange,
74 | onChange: widget.onChange,
75 | pageSize: widget.pageSize,
76 | totalPage: totalPage,
77 | child: Wrap(
78 | direction: Axis.horizontal,
79 | spacing: 8,
80 | children: [
81 | const _PaginationArrowItem(arrow: 'left'),
82 | Wrap(
83 | direction: Axis.horizontal,
84 | spacing: 8,
85 | children: List.generate(
86 | totalPage,
87 | (index) => _PaginationItem(page: index),
88 | ),
89 | ),
90 | const _PaginationArrowItem(arrow: 'right'),
91 | ],
92 | ),
93 | );
94 | }
95 |
96 | int _calculateTotalPage() {
97 | return (widget.total / widget.pageSize).ceil();
98 | }
99 |
100 | void _handleChange(int page) {
101 | if (widget.controller != null) {
102 | widget.controller!.current = page;
103 | }
104 | setState(() {
105 | current = page;
106 | });
107 | }
108 | }
109 |
110 | class PaginationController extends ChangeNotifier {
111 | int current = 0;
112 | }
113 |
114 | class _PaginationArrowItem extends StatefulWidget {
115 | const _PaginationArrowItem({Key? key, required this.arrow}) : super(key: key);
116 |
117 | final String arrow;
118 |
119 | @override
120 | State<_PaginationArrowItem> createState() => __PaginationArowItemState();
121 | }
122 |
123 | class __PaginationArowItemState extends State<_PaginationArrowItem> {
124 | bool hovered = false;
125 |
126 | @override
127 | Widget build(BuildContext context) {
128 | return MouseRegion(
129 | cursor: _available()
130 | ? SystemMouseCursors.click
131 | : SystemMouseCursors.forbidden,
132 | onEnter: (_) => setState(() {
133 | hovered = true;
134 | }),
135 | onExit: (_) => setState(() {
136 | hovered = false;
137 | }),
138 | child: GestureDetector(
139 | onTap: _handleTap,
140 | child: Container(
141 | decoration: BoxDecoration(
142 | border: Border.all(
143 | color: _available()
144 | ? hovered
145 | ? Colors.blue_6
146 | : Colors.gray_5
147 | : Colors.gray_5,
148 | ),
149 | borderRadius: BorderRadius.circular(2),
150 | ),
151 | height: 32,
152 | width: 32,
153 | child: Center(
154 | child: IconTheme.merge(
155 | child: Icon(widget.arrow == 'left'
156 | ? Icons.chevron_left
157 | : Icons.chevron_right),
158 | data: IconThemeData(
159 | color: _available()
160 | ? hovered
161 | ? Colors.blue_6
162 | : Colors.black
163 | : Colors.gray_5,
164 | ),
165 | ),
166 | ),
167 | ),
168 | ),
169 | );
170 | }
171 |
172 | bool _available() {
173 | bool available = true;
174 | var current = _PaginationInhertedWidget.of(context)?.current ?? 0;
175 | var totalPage = _PaginationInhertedWidget.of(context)!.totalPage ?? 0;
176 | if (widget.arrow == 'left' && current == 0) {
177 | available = false;
178 | } else if (widget.arrow == 'right' && current == totalPage - 1) {
179 | available = false;
180 | }
181 | return available;
182 | }
183 |
184 | void _handleTap() {
185 | var current = _PaginationInhertedWidget.of(context)?.current ?? 0;
186 | var handleChange = _PaginationInhertedWidget.of(context)!.handleChange;
187 | var totalPage = _PaginationInhertedWidget.of(context)!.totalPage ?? 0;
188 |
189 | var page = current - 1 >= 0 ? current - 1 : current;
190 | if (widget.arrow != 'left') {
191 | page = current + 1 <= totalPage - 1 ? current + 1 : current;
192 | }
193 | handleChange(page);
194 | var onChange = _PaginationInhertedWidget.of(context)?.onChange;
195 | var pageSize = _PaginationInhertedWidget.of(context)!.pageSize ?? 10;
196 | if (onChange != null) {
197 | onChange(page, pageSize);
198 | }
199 | }
200 | }
201 |
202 | class _PaginationItem extends StatefulWidget {
203 | const _PaginationItem({Key? key, required this.page}) : super(key: key);
204 |
205 | final int page;
206 |
207 | @override
208 | State<_PaginationItem> createState() => __PaginationItemState();
209 | }
210 |
211 | class __PaginationItemState extends State<_PaginationItem> {
212 | bool hovered = false;
213 |
214 | @override
215 | Widget build(BuildContext context) {
216 | var current = _PaginationInhertedWidget.of(context)?.current ?? 0;
217 |
218 | return MouseRegion(
219 | cursor: SystemMouseCursors.click,
220 | onEnter: (_) => setState(() {
221 | hovered = true;
222 | }),
223 | onExit: (_) => setState(() {
224 | hovered = false;
225 | }),
226 | child: GestureDetector(
227 | onTap: _handleTap,
228 | child: Container(
229 | decoration: BoxDecoration(
230 | border: Border.all(
231 | color: current == widget.page || hovered
232 | ? Colors.blue_6
233 | : Colors.gray_5,
234 | ),
235 | borderRadius: BorderRadius.circular(2),
236 | ),
237 | height: 32,
238 | width: 32,
239 | child: Center(
240 | child: DefaultTextStyle.merge(
241 | child: Text('${widget.page + 1}'),
242 | style: TextStyle(
243 | color:
244 | current == widget.page || hovered ? Colors.blue_6 : null),
245 | )),
246 | ),
247 | ),
248 | );
249 | }
250 |
251 | void _handleTap() {
252 | var handleChange = _PaginationInhertedWidget.of(context)!.handleChange;
253 | handleChange(widget.page);
254 | var onChange = _PaginationInhertedWidget.of(context)?.onChange;
255 | if (onChange != null) {
256 | onChange(
257 | widget.page,
258 | _PaginationInhertedWidget.of(context)?.pageSize ?? 10,
259 | );
260 | }
261 | }
262 | }
263 |
264 | class _PaginationInhertedWidget extends InheritedWidget {
265 | const _PaginationInhertedWidget({
266 | required Widget child,
267 | Key? key,
268 | this.current,
269 | required this.handleChange,
270 | this.onChange,
271 | this.pageSize,
272 | this.totalPage,
273 | }) : super(child: child, key: key);
274 |
275 | final int? current;
276 | final void Function(int current) handleChange;
277 | final void Function(int page, int pageSize)? onChange;
278 | final int? pageSize;
279 | final int? totalPage;
280 |
281 | static _PaginationInhertedWidget? of(BuildContext context) {
282 | return context
283 | .dependOnInheritedWidgetOfExactType<_PaginationInhertedWidget>();
284 | }
285 |
286 | @override
287 | bool updateShouldNotify(_PaginationInhertedWidget oldWidget) {
288 | return oldWidget.current != current;
289 | }
290 | }
291 |
--------------------------------------------------------------------------------
/lib/src/widget/popconfirm.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/popconfirm.dart
--------------------------------------------------------------------------------
/lib/src/widget/popover.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/popover.dart
--------------------------------------------------------------------------------
/lib/src/widget/progress.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/progress.dart
--------------------------------------------------------------------------------
/lib/src/widget/qr_code.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/qr_code.dart
--------------------------------------------------------------------------------
/lib/src/widget/radio.dart:
--------------------------------------------------------------------------------
1 | import 'package:ant_design_flutter/src/style/color.dart';
2 | import 'package:flutter/widgets.dart';
3 |
4 | class Radio extends StatefulWidget {
5 | const Radio({Key? key, this.child, this.controller, this.disabled = false})
6 | : super(key: key);
7 |
8 | final Widget? child;
9 | final RadioController? controller;
10 | final bool disabled;
11 |
12 | @override
13 | State createState() => _RadioState();
14 | }
15 |
16 | class _RadioState extends State {
17 | bool checked = false;
18 | bool hovered = false;
19 |
20 | @override
21 | void initState() {
22 | super.initState();
23 | setState(() {
24 | checked = widget.controller?.value ?? false;
25 | });
26 | }
27 |
28 | @override
29 | Widget build(BuildContext context) {
30 | Widget circle = Container(
31 | decoration: BoxDecoration(
32 | border: Border.all(
33 | color: widget.disabled ? Colors.gray_6 : Colors.gray_5,
34 | ),
35 | shape: BoxShape.circle,
36 | ),
37 | height: 16,
38 | width: 16,
39 | );
40 |
41 | Widget dot = checked
42 | ? Container(
43 | decoration: BoxDecoration(
44 | color: widget.disabled ? Colors.gray_6 : Colors.blue_6,
45 | shape: BoxShape.circle,
46 | ),
47 | height: 8,
48 | width: 8,
49 | )
50 | : const SizedBox();
51 |
52 | Widget text = widget.child != null
53 | ? Padding(
54 | padding: const EdgeInsets.symmetric(horizontal: 8.0),
55 | child: widget.child,
56 | )
57 | : const SizedBox();
58 |
59 | TextStyle style = TextStyle(color: widget.disabled ? Colors.gray_6 : null);
60 |
61 | MouseCursor cursor = widget.disabled
62 | ? SystemMouseCursors.forbidden
63 | : SystemMouseCursors.click;
64 |
65 | return MouseRegion(
66 | cursor: cursor,
67 | child: GestureDetector(
68 | onTap: _handleTap,
69 | child: DefaultTextStyle.merge(
70 | child: Row(
71 | children: [
72 | Stack(
73 | alignment: AlignmentDirectional.center,
74 | children: [circle, dot],
75 | ),
76 | text,
77 | ],
78 | ),
79 | style: style,
80 | ),
81 | ),
82 | );
83 | }
84 |
85 | void _handleTap() {
86 | if (!widget.disabled) {
87 | setState(() {
88 | checked = true;
89 | });
90 | }
91 | }
92 | }
93 |
94 | class RadioController extends ChangeNotifier {
95 | bool value = false;
96 | }
97 |
--------------------------------------------------------------------------------
/lib/src/widget/rate.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/rate.dart
--------------------------------------------------------------------------------
/lib/src/widget/result.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/result.dart
--------------------------------------------------------------------------------
/lib/src/widget/scaffold.dart:
--------------------------------------------------------------------------------
1 | import 'package:ant_design_flutter/src/style/color.dart';
2 | import 'package:flutter/material.dart' as material show Scaffold;
3 | import 'package:flutter/widgets.dart';
4 |
5 | /// A scaffold of ant design flutter's widget which provides a default text style
6 | /// and icon theme.
7 | ///
8 | /// This scaffold only has body and floating action button if you ever need to do
9 | /// some extra work. Basicly, body is the only widget you should put in this.
10 | class Scaffold extends StatelessWidget {
11 | const Scaffold({Key? key, required this.body})
12 | : floatingActionButton = null,
13 | super(key: key);
14 |
15 | const Scaffold.floatingActionButton({
16 | Key? key,
17 | required this.body,
18 | this.floatingActionButton,
19 | }) : super(key: key);
20 |
21 | final Widget body;
22 | final Widget? floatingActionButton;
23 |
24 | @override
25 | Widget build(BuildContext context) {
26 | return material.Scaffold(
27 | body: DefaultTextStyle(
28 | style: TextStyle(
29 | color: Colors.black.withOpacity(0.85),
30 | fontWeight: FontWeight.w400,
31 | fontSize: 14,
32 | ),
33 | child: IconTheme(
34 | data: const IconThemeData(color: Colors.gray_7, size: 16),
35 | child: body,
36 | ),
37 | ),
38 | floatingActionButton: floatingActionButton,
39 | );
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/src/widget/segmented.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/segmented.dart
--------------------------------------------------------------------------------
/lib/src/widget/select.dart:
--------------------------------------------------------------------------------
1 | import 'package:ant_design_flutter/src/enum/size.dart';
2 | import 'package:ant_design_flutter/src/enum/status.dart';
3 | import 'package:ant_design_flutter/src/style/color.dart';
4 | import 'package:ant_design_flutter/src/style/icon.dart';
5 | import 'package:flutter/material.dart'
6 | show InputBorder, InputDecoration, TextField;
7 | import 'package:flutter/widgets.dart';
8 |
9 | class Select extends StatefulWidget {
10 | const Select({
11 | Key? key,
12 | this.allowClear = false,
13 | this.autoClearSearchValue = true,
14 | this.bordered = true,
15 | this.clearIcon,
16 | this.controller,
17 | this.defaultActiveFirstOption = true,
18 | this.defaultOpen = false,
19 | this.disabled = false,
20 | this.dropdownSelectWidth,
21 | this.dropdownBuilder,
22 | this.filterOption,
23 | this.filterSort,
24 | this.labelInValue = false,
25 | this.listHeight = 256,
26 | this.loading = false,
27 | this.maxTagCount,
28 | this.maxTagPlaceholder,
29 | this.maxTagTextLength,
30 | this.menuItemSelectedIcon,
31 | this.mode = SelectMode.normal,
32 | this.notFoundContent = const Text('Not Found'),
33 | this.onBlur,
34 | this.onChange,
35 | this.onClear,
36 | this.onDeselect,
37 | this.onDropdownVisibleChange,
38 | this.onFocus,
39 | this.onInputKeyDown,
40 | this.onMouseEnter,
41 | this.onMouseLeave,
42 | this.onPopupScroll,
43 | this.onSearch,
44 | this.onSelect,
45 | this.optionFilterProp = OptionProp.value,
46 | this.optionLabelProp = OptionProp.children,
47 | this.options,
48 | this.placeholder,
49 | this.removeIcon,
50 | this.showArrow,
51 | this.showSearch = false,
52 | this.size = Size.middle,
53 | this.status,
54 | this.suffixIcon,
55 | this.tagBuilder,
56 | this.tokenSeparators,
57 | this.virtual = true,
58 | required this.children,
59 | }) : super(key: key);
60 |
61 | final bool allowClear;
62 | final bool autoClearSearchValue;
63 | final bool bordered;
64 | final Widget? clearIcon;
65 | final SelectController? controller;
66 | final bool defaultActiveFirstOption;
67 | final bool defaultOpen;
68 | final bool disabled;
69 | final double? dropdownSelectWidth;
70 | final Widget Function()? dropdownBuilder;
71 | final bool Function()? filterOption;
72 | final int Function()? filterSort;
73 | final bool labelInValue;
74 | final double listHeight;
75 | final bool loading;
76 | final int? maxTagCount;
77 | final Widget? maxTagPlaceholder;
78 | final int? maxTagTextLength;
79 | final Widget? menuItemSelectedIcon;
80 | final SelectMode mode;
81 | final Widget notFoundContent;
82 | final void Function()? onBlur;
83 | final void Function()? onChange;
84 | final void Function()? onClear;
85 | final void Function()? onDeselect;
86 | final void Function()? onDropdownVisibleChange;
87 | final void Function()? onFocus;
88 | final void Function()? onInputKeyDown;
89 | final void Function()? onMouseEnter;
90 | final void Function()? onMouseLeave;
91 | final void Function()? onPopupScroll;
92 | final void Function()? onSearch;
93 | final void Function()? onSelect;
94 | final OptionProp optionFilterProp;
95 | final OptionProp optionLabelProp;
96 | final Map? options;
97 | final String? placeholder;
98 | final Widget? removeIcon;
99 | final bool? showArrow;
100 | final bool showSearch;
101 | final Size size;
102 | final Status? status;
103 | final Widget? suffixIcon;
104 | final Widget Function()? tagBuilder;
105 | final List? tokenSeparators;
106 | final bool virtual;
107 | final List> children;
108 |
109 | @override
110 | State createState() => _SelectState();
111 | }
112 |
113 | class _SelectState extends State with SingleTickerProviderStateMixin {
114 | static const height = {
115 | Size.small: 24.0,
116 | Size.middle: 32.0,
117 | Size.large: 40.0,
118 | };
119 |
120 | bool actived = false;
121 | late OverlayEntry entry;
122 | FocusNode focusNode = FocusNode();
123 | bool hovered = false;
124 | LayerLink link = LayerLink();
125 | TextEditingController textEditingController = TextEditingController();
126 | late AnimationController animatedController;
127 |
128 | @override
129 | void initState() {
130 | super.initState();
131 | focusNode.addListener(_focusNodeListener);
132 | setState(() {
133 | textEditingController.text =
134 | widget.controller?.selected[0].toString() ?? '';
135 | });
136 | textEditingController.addListener(() {
137 | widget.controller?.selected[0] = textEditingController.text;
138 | });
139 | animatedController = AnimationController(
140 | vsync: this,
141 | duration: const Duration(seconds: 1),
142 | )..repeat();
143 | }
144 |
145 | @override
146 | void dispose() {
147 | focusNode.removeListener(_focusNodeListener);
148 | focusNode.dispose();
149 | textEditingController.dispose();
150 | animatedController.dispose();
151 | super.dispose();
152 | }
153 |
154 | @override
155 | Widget build(BuildContext context) {
156 | return MouseRegion(
157 | cursor: widget.disabled
158 | ? SystemMouseCursors.forbidden
159 | : SystemMouseCursors.click,
160 | onEnter: (_) {
161 | if (!widget.disabled) {
162 | setState(() {
163 | hovered = true;
164 | });
165 | }
166 | },
167 | onExit: (_) {
168 | if (!widget.disabled) {
169 | setState(() {
170 | hovered = false;
171 | });
172 | }
173 | },
174 | child: GestureDetector(
175 | child: CompositedTransformTarget(
176 | link: link,
177 | child: Container(
178 | decoration: BoxDecoration(
179 | border: Border.all(
180 | color: widget.disabled
181 | ? Colors.gray_5
182 | : actived || hovered
183 | ? Colors.blue_6
184 | : Colors.gray_5,
185 | ),
186 | borderRadius: BorderRadius.circular(2),
187 | boxShadow: actived
188 | ? const [
189 | BoxShadow(
190 | blurRadius: 1,
191 | color: Colors.blue_6,
192 | offset: Offset(1, 1),
193 | spreadRadius: 0.1,
194 | ),
195 | BoxShadow(
196 | blurRadius: 1,
197 | color: Colors.blue_6,
198 | offset: Offset(-1, -1),
199 | spreadRadius: 0.1,
200 | ),
201 | ]
202 | : null,
203 | color: widget.disabled ? Colors.gray_3 : Colors.white,
204 | ),
205 | height: height[widget.size],
206 | padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
207 | child: Row(
208 | children: [
209 | Expanded(
210 | child: Center(
211 | child: TextField(
212 | controller: textEditingController,
213 | decoration: InputDecoration(
214 | border: InputBorder.none,
215 | hintText: widget.placeholder,
216 | hintStyle:
217 | const TextStyle(color: Colors.gray_5, fontSize: 14),
218 | isCollapsed: true,
219 | ),
220 | enabled: !widget.disabled,
221 | focusNode: focusNode,
222 | mouseCursor: widget.disabled
223 | ? SystemMouseCursors.forbidden
224 | : SystemMouseCursors.click,
225 | readOnly: true,
226 | showCursor: widget.showSearch,
227 | style: TextStyle(
228 | color: widget.disabled ? Colors.gray_5 : Colors.gray_10,
229 | fontSize: 14,
230 | ),
231 | ),
232 | ),
233 | ),
234 | widget.loading
235 | ? RotationTransition(
236 | turns: animatedController,
237 | child: const Icon(
238 | Icons.loading,
239 | ),
240 | )
241 | : widget.allowClear && hovered
242 | ? GestureDetector(
243 | onTap: _handleClear,
244 | child: const Icon(Icons.clear),
245 | )
246 | : const Icon(Icons.chevron_down)
247 | ],
248 | ),
249 | ),
250 | ),
251 | onTap: () {
252 | if (!widget.disabled) {
253 | FocusScope.of(context).requestFocus(focusNode);
254 | }
255 | },
256 | ),
257 | );
258 | }
259 |
260 | void _focusNodeListener() {
261 | if (focusNode.hasFocus) {
262 | setState(() {
263 | actived = true;
264 | });
265 | var size = context.size;
266 | entry = OverlayEntry(
267 | builder: (context) => Positioned(
268 | width: size?.width,
269 | child: CompositedTransformFollower(
270 | followerAnchor: Alignment.topCenter,
271 | link: link,
272 | offset: const Offset(0, 8),
273 | showWhenUnlinked: false,
274 | targetAnchor: Alignment.bottomCenter,
275 | child: _SelectDropdown(
276 | children: widget.children
277 | .map((child) => GestureDetector(
278 | child: _DecoratedOption(
279 | selected: child.value == textEditingController.text,
280 | child: child,
281 | ),
282 | onTap: () => _handleTap(child),
283 | ))
284 | .toList()),
285 | ),
286 | ),
287 | );
288 | Overlay.of(context).insert(entry);
289 | } else {
290 | setState(() {
291 | actived = false;
292 | });
293 | entry.remove();
294 | }
295 | }
296 |
297 | void _handleTap(Option option) {
298 | if (!option.disabled) {
299 | setState(() {
300 | textEditingController.text = option.value;
301 | });
302 | widget.controller?.selected = [option.value];
303 | focusNode.unfocus();
304 | }
305 | }
306 |
307 | void _handleClear() {
308 | if (!widget.disabled) {
309 | setState(() {
310 | textEditingController.text = '';
311 | });
312 | widget.controller?.selected = [''];
313 | focusNode.unfocus();
314 | }
315 | }
316 | }
317 |
318 | class SelectController extends ChangeNotifier {
319 | List selected = [];
320 | }
321 |
322 | class Option extends StatelessWidget {
323 | const Option({
324 | Key? key,
325 | this.child,
326 | this.disabled = false,
327 | this.title,
328 | required this.value,
329 | }) : super(key: key);
330 |
331 | final Widget? child;
332 | final bool disabled;
333 | final String? title;
334 | final T value;
335 |
336 | @override
337 | Widget build(BuildContext context) {
338 | return child ?? Text(value.toString());
339 | }
340 | }
341 |
342 | class _DecoratedOption extends StatefulWidget {
343 | const _DecoratedOption({
344 | Key? key,
345 | required this.child,
346 | required this.selected,
347 | }) : super(key: key);
348 |
349 | final Option child;
350 | final bool selected;
351 |
352 | @override
353 | State<_DecoratedOption> createState() => __DecoratedOptionState();
354 | }
355 |
356 | class __DecoratedOptionState extends State<_DecoratedOption> {
357 | bool hovered = false;
358 |
359 | @override
360 | Widget build(BuildContext context) {
361 | return MouseRegion(
362 | cursor: widget.child.disabled
363 | ? SystemMouseCursors.forbidden
364 | : SystemMouseCursors.click,
365 | onEnter: (_) => setState(() {
366 | if (!widget.child.disabled) {
367 | hovered = true;
368 | }
369 | }),
370 | onExit: (_) => setState(() {
371 | hovered = false;
372 | }),
373 | child: Container(
374 | decoration: BoxDecoration(
375 | color: widget.selected
376 | ? Colors.blue_1
377 | : hovered
378 | ? Colors.gray_2
379 | : null,
380 | ),
381 | height: 32,
382 | padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
383 | child: DefaultTextStyle(
384 | style: TextStyle(
385 | color: widget.child.disabled ? Colors.gray_5 : Colors.gray_10,
386 | fontSize: 14,
387 | ),
388 | child: widget.child,
389 | ),
390 | ),
391 | );
392 | }
393 | }
394 |
395 | class _SelectDropdown extends StatelessWidget {
396 | const _SelectDropdown({Key? key, this.children}) : super(key: key);
397 |
398 | final List? children;
399 |
400 | @override
401 | Widget build(BuildContext context) {
402 | return ConstrainedBox(
403 | constraints: const BoxConstraints(maxHeight: 256),
404 | child: Container(
405 | decoration: const BoxDecoration(color: Colors.white, boxShadow: [
406 | BoxShadow(
407 | blurRadius: 4,
408 | color: Colors.gray_3,
409 | offset: Offset(4, 4),
410 | spreadRadius: 0.1,
411 | ),
412 | BoxShadow(
413 | blurRadius: 4,
414 | color: Colors.gray_3,
415 | offset: Offset(-4, 0),
416 | spreadRadius: 0.1,
417 | ),
418 | ]),
419 | child: ListView(
420 | children: children ?? [],
421 | ),
422 | ),
423 | );
424 | }
425 | }
426 |
427 | enum OptionProp { children, label, value }
428 |
429 | enum SelectMode { multiple, normal, tags }
430 |
--------------------------------------------------------------------------------
/lib/src/widget/skeleton.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/skeleton.dart
--------------------------------------------------------------------------------
/lib/src/widget/slider.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 |
3 | import 'package:ant_design_flutter/src/enum/placement.dart';
4 | import 'package:ant_design_flutter/src/style/color.dart';
5 | import 'package:flutter/gestures.dart';
6 | import 'package:flutter/material.dart' show Material;
7 | import 'package:flutter/widgets.dart';
8 |
9 | class Slider extends StatefulWidget {
10 | const Slider({
11 | Key? key,
12 | this.allowClear = false,
13 | this.controller,
14 | this.disabled = false,
15 | this.dots = false,
16 | this.draggableTrack = false,
17 | this.included = true,
18 | this.marks,
19 | this.max = 100,
20 | this.min = 0,
21 | this.range = false,
22 | this.reverse = false,
23 | this.step = 1,
24 | this.tipFormatter,
25 | this.tooltipPlacement,
26 | this.tooltipVisible,
27 | this.vertical = false,
28 | this.onAfterChange,
29 | this.onChange,
30 | }) : super(key: key);
31 |
32 | final bool allowClear;
33 | final SliderController? controller;
34 | final bool disabled;
35 | final bool dots;
36 | final bool draggableTrack;
37 | final bool included;
38 | final List? marks;
39 | final double max;
40 | final double min;
41 | final bool range;
42 | final bool reverse;
43 | final double step;
44 | final Widget Function(double value)? tipFormatter;
45 | final Placement? tooltipPlacement;
46 | final bool? tooltipVisible;
47 | final bool vertical;
48 | final void Function(double value)? onAfterChange;
49 | final void Function(double value)? onChange;
50 |
51 | @override
52 | State createState() => _SliderState();
53 | }
54 |
55 | class _SliderState extends State {
56 | double value = 0;
57 | bool hovered = false;
58 | bool pressed = false;
59 |
60 | LayerLink link = LayerLink();
61 | late OverlayEntry entry;
62 |
63 | @override
64 | void initState() {
65 | super.initState();
66 | setState(() {
67 | value = widget.controller?.value ?? 0;
68 | });
69 | }
70 |
71 | @override
72 | Widget build(BuildContext context) {
73 | return LayoutBuilder(builder: (
74 | BuildContext context,
75 | BoxConstraints constraints,
76 | ) {
77 | final double width = constraints.maxWidth - 14;
78 |
79 | Widget activedTrack = GestureDetector(
80 | child: Container(
81 | decoration: const BoxDecoration(
82 | borderRadius: BorderRadius.only(
83 | bottomLeft: Radius.circular(2),
84 | topLeft: Radius.circular(2),
85 | ),
86 | color: Colors.blue_5,
87 | ),
88 | height: 4,
89 | width: width / widget.max * value,
90 | ),
91 | onTapDown: (TapDownDetails details) =>
92 | _handleTapDown(details, width, negative: true),
93 | );
94 |
95 | Widget draggableCircle = Listener(
96 | onPointerDown: _handlePointerDown,
97 | onPointerUp: _handlePointerUp,
98 | child: GestureDetector(
99 | child: Container(
100 | decoration: BoxDecoration(
101 | border: Border.all(
102 | color: Colors.blue_6,
103 | width: 2,
104 | ),
105 | shape: BoxShape.circle,
106 | ),
107 | height: 14,
108 | width: 14,
109 | ),
110 | onHorizontalDragUpdate: (DragUpdateDetails details) =>
111 | _handleDragUpdate(details, width),
112 | ),
113 | );
114 |
115 | Widget unactivedTrack = Expanded(
116 | child: GestureDetector(
117 | child: Container(
118 | decoration: const BoxDecoration(
119 | borderRadius: BorderRadius.only(
120 | bottomRight: Radius.circular(2),
121 | topRight: Radius.circular(2),
122 | ),
123 | color: Colors.gray_4,
124 | ),
125 | height: 4,
126 | ),
127 | onTapDown: (TapDownDetails details) => _handleTapDown(details, width),
128 | ),
129 | );
130 |
131 | return MouseRegion(
132 | cursor: hovered ? SystemMouseCursors.click : MouseCursor.defer,
133 | onEnter: _handleEnter,
134 | onExit: _handleExit,
135 | child: Row(
136 | children: [
137 | activedTrack,
138 | CompositedTransformTarget(link: link, child: draggableCircle),
139 | unactivedTrack
140 | ],
141 | ),
142 | );
143 | });
144 | }
145 |
146 | void _handleTapDown(
147 | TapDownDetails details,
148 | double width, {
149 | bool negative = false,
150 | }) {
151 | double newValue = details.localPosition.dx / width * widget.max;
152 | if (!negative) {
153 | newValue = newValue + value;
154 | }
155 |
156 | widget.controller?.value = newValue.roundToDouble();
157 |
158 | setState(() {
159 | value = newValue;
160 | });
161 | entry.markNeedsBuild();
162 | }
163 |
164 | void _handleDragUpdate(DragUpdateDetails details, double width) {
165 | double newValue = value + details.delta.dx / width * widget.max;
166 | if (newValue < widget.min) {
167 | newValue = widget.min;
168 | } else if (newValue > widget.max) {
169 | newValue = widget.max;
170 | }
171 |
172 | widget.controller?.value = newValue.roundToDouble();
173 |
174 | setState(() {
175 | value = newValue;
176 | });
177 | entry.markNeedsBuild();
178 | }
179 |
180 | void _handlePointerDown(PointerDownEvent event) {
181 | setState(() {
182 | pressed = true;
183 | });
184 | }
185 |
186 | void _handlePointerUp(PointerUpEvent event) {
187 | setState(() {
188 | pressed = false;
189 | });
190 | }
191 |
192 | void _handleEnter(PointerEnterEvent event) {
193 | setState(() {
194 | hovered = true;
195 | });
196 | entry = _buildOverlayEntry();
197 | Overlay.of(context).insert(entry);
198 | }
199 |
200 | void _handleExit(PointerExitEvent event) {
201 | setState(() {
202 | hovered = false;
203 | });
204 | if (!pressed) {
205 | entry.remove();
206 | }
207 | }
208 |
209 | OverlayEntry _buildOverlayEntry() {
210 | var offset = Offset(0, -1 * context.size!.height);
211 | return OverlayEntry(
212 | builder: (context) => Positioned(
213 | height: 38,
214 | child: CompositedTransformFollower(
215 | followerAnchor: Alignment.bottomCenter,
216 | link: link,
217 | offset: offset,
218 | showWhenUnlinked: false,
219 | targetAnchor: Alignment.topCenter,
220 | child: _SliderOverlayEntry(label: value.roundToDouble().toString()),
221 | ),
222 | ),
223 | );
224 | }
225 | }
226 |
227 | class SliderController extends ChangeNotifier {
228 | double value = 0;
229 | }
230 |
231 | class _SliderOverlayEntry extends StatelessWidget {
232 | const _SliderOverlayEntry({Key? key, required this.label}) : super(key: key);
233 |
234 | final String label;
235 |
236 | @override
237 | Widget build(BuildContext context) {
238 | return Material(
239 | child: Stack(
240 | alignment: AlignmentDirectional.bottomCenter,
241 | clipBehavior: Clip.none,
242 | children: [
243 | Positioned(
244 | bottom: -4,
245 | child: Transform.rotate(
246 | angle: pi / 4,
247 | child: Container(
248 | decoration: const BoxDecoration(
249 | borderRadius: BorderRadius.only(
250 | bottomRight: Radius.circular(2),
251 | ),
252 | color: Colors.gray_10,
253 | ),
254 | height: 8,
255 | width: 8,
256 | ),
257 | ),
258 | ),
259 | Container(
260 | alignment: AlignmentDirectional.center,
261 | decoration: BoxDecoration(
262 | borderRadius: BorderRadius.circular(2),
263 | color: Colors.gray_10,
264 | ),
265 | padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 12),
266 | child: Text(
267 | label,
268 | style: const TextStyle(
269 | color: Colors.white,
270 | fontSize: 14,
271 | height: 1,
272 | ),
273 | ),
274 | ),
275 | ],
276 | ),
277 | );
278 | }
279 | }
280 |
--------------------------------------------------------------------------------
/lib/src/widget/space.dart:
--------------------------------------------------------------------------------
1 | import 'package:ant_design_flutter/src/enum/size.dart';
2 | import 'package:flutter/widgets.dart';
3 |
4 | class Space extends StatelessWidget {
5 | const Space({
6 | Key? key,
7 | required this.children,
8 | this.align,
9 | this.direction = Axis.horizontal,
10 | this.size = Size.small,
11 | this.split,
12 | this.wrap = false,
13 | }) : super(key: key);
14 |
15 | final List children;
16 | final SpaceAlign? align;
17 | final Axis direction;
18 | final Size size;
19 | final Widget? split;
20 | final bool wrap;
21 |
22 | @override
23 | Widget build(BuildContext context) {
24 | return Wrap(
25 | direction: direction,
26 | crossAxisAlignment: Axis.horizontal == direction
27 | ? WrapCrossAlignment.center
28 | : WrapCrossAlignment.start,
29 | runSpacing: _calculateSpacing(),
30 | spacing: _calculateSpacing(),
31 | children: children,
32 | );
33 | }
34 |
35 | double _calculateSpacing() {
36 | var spacing = 8.0;
37 | if (Size.middle == size) {
38 | spacing = 16.0;
39 | } else if (Size.large == size) {
40 | spacing = 24.0;
41 | }
42 | return spacing;
43 | }
44 | }
45 |
46 | enum SpaceAlign { start, end, center, baseline }
47 |
--------------------------------------------------------------------------------
/lib/src/widget/spin.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/spin.dart
--------------------------------------------------------------------------------
/lib/src/widget/statistic.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/statistic.dart
--------------------------------------------------------------------------------
/lib/src/widget/steps.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/widgets.dart';
2 |
3 | class Steps extends StatefulWidget {
4 | const Steps({
5 | Key? key,
6 | required this.children,
7 | this.current = 0,
8 | this.direction = Axis.horizontal,
9 | this.initial = 0,
10 | this.labelPlacement = Axis.horizontal,
11 | this.percent,
12 | this.progressDot,
13 | this.responsive = true,
14 | this.size = StepsSize.middle,
15 | this.status = StepsStatus.process,
16 | this.type = StepsType.normal,
17 | this.onChange,
18 | }) : super(key: key);
19 |
20 | final List children;
21 | final int current;
22 | final Axis direction;
23 | final int initial;
24 | final Axis labelPlacement;
25 | final double? percent;
26 | final Widget? progressDot;
27 | final bool responsive;
28 | final StepsSize size;
29 | final StepsStatus status;
30 | final StepsType type;
31 | final void Function(int current)? onChange;
32 |
33 | @override
34 | State createState() => _StepsState();
35 | }
36 |
37 | class _StepsState extends State {
38 | @override
39 | Widget build(BuildContext context) {
40 | return Container();
41 | }
42 | }
43 |
44 | enum StepsSize { middle, small }
45 |
46 | enum StepsStatus { wait, process, finish, error }
47 |
48 | enum StepsType { normal, navigation }
49 |
--------------------------------------------------------------------------------
/lib/src/widget/switch.dart:
--------------------------------------------------------------------------------
1 | import 'package:ant_design_flutter/src/enum/size.dart';
2 | import 'package:ant_design_flutter/src/style/color.dart';
3 | import 'package:flutter/widgets.dart';
4 | import 'package:flutter_spinkit/flutter_spinkit.dart';
5 |
6 | class Switch extends StatefulWidget {
7 | const Switch({
8 | Key? key,
9 | this.autoFocus = false,
10 | this.checkedChildren,
11 | this.controller,
12 | this.disabled = false,
13 | this.loading = false,
14 | this.size = Size.middle,
15 | this.uncheckedChildren,
16 | this.onChange,
17 | this.onClick,
18 | }) : super(key: key);
19 |
20 | final bool autoFocus;
21 | final Widget? checkedChildren;
22 | final SwitchController? controller;
23 | final bool disabled;
24 | final bool loading;
25 | final Size size;
26 | final Widget? uncheckedChildren;
27 | final void Function(bool checked)? onChange;
28 | final void Function(bool checked)? onClick;
29 |
30 | @override
31 | State createState() => _SwitchState();
32 | }
33 |
34 | class _SwitchState extends State {
35 | bool checked = false;
36 |
37 | @override
38 | void initState() {
39 | super.initState();
40 | setState(() {
41 | checked = widget.controller?.checked ?? false;
42 | });
43 | }
44 |
45 | @override
46 | Widget build(BuildContext context) {
47 | double height = widget.size == Size.small ? 16 : 22;
48 | double width = widget.size == Size.small ? 12 : 18;
49 |
50 | Widget left = const SizedBox();
51 | if (checked) {
52 | left = widget.checkedChildren ?? SizedBox(width: width + 2);
53 | }
54 |
55 | Widget loading = SpinKitFadingCircle(color: Colors.blue_3, size: width - 2);
56 |
57 | Widget circle = Container(
58 | decoration: const BoxDecoration(
59 | color: Colors.white,
60 | shape: BoxShape.circle,
61 | ),
62 | height: width,
63 | width: width,
64 | child: widget.loading ? loading : null,
65 | );
66 |
67 | Widget right = widget.uncheckedChildren ?? SizedBox(width: width + 2);
68 | if (checked) {
69 | right = const SizedBox();
70 | }
71 |
72 | Color color = widget.loading ? Colors.gray_3 : Colors.gray_5;
73 | if (checked) {
74 | color = widget.loading ? Colors.blue_3 : Colors.blue_6;
75 | }
76 |
77 | return MouseRegion(
78 | cursor: widget.disabled || widget.loading
79 | ? SystemMouseCursors.forbidden
80 | : SystemMouseCursors.click,
81 | child: GestureDetector(
82 | onTap: _handleTap,
83 | child: Container(
84 | decoration: BoxDecoration(
85 | borderRadius: BorderRadius.circular(11),
86 | color: color,
87 | ),
88 | height: height,
89 | padding: const EdgeInsets.all(2),
90 | child: Row(
91 | mainAxisSize: MainAxisSize.min,
92 | children: [left, circle, right],
93 | ),
94 | ),
95 | ),
96 | );
97 | }
98 |
99 | void _handleTap() {
100 | if (!widget.disabled && !widget.loading) {
101 | widget.controller?.checked = !checked;
102 | widget.onChange?.call(!checked);
103 | widget.onClick?.call(!checked);
104 | setState(() {
105 | checked = !checked;
106 | });
107 | }
108 | }
109 | }
110 |
111 | class SwitchController extends ChangeNotifier {
112 | bool checked = false;
113 | }
114 |
--------------------------------------------------------------------------------
/lib/src/widget/table.dart:
--------------------------------------------------------------------------------
1 | import 'package:ant_design_flutter/src/style/color.dart';
2 | import 'package:flutter/widgets.dart' as widgets;
3 |
4 | class Table extends widgets.StatefulWidget {
5 | const Table({
6 | widgets.Key? key,
7 | this.bordered = false,
8 | required this.columns,
9 | required this.dataSource,
10 | }) : super(key: key);
11 |
12 | final bool bordered;
13 | final List columns;
14 | final List dataSource;
15 |
16 | @override
17 | widgets.State createState() => _TableState();
18 | }
19 |
20 | class _TableState extends widgets.State {
21 | int? hoveredRow;
22 |
23 | @override
24 | widgets.Widget build(widgets.BuildContext context) {
25 | widgets.TableRow header = widgets.TableRow(
26 | children: widget.columns.map((column) {
27 | return widgets.Container(
28 | padding: const widgets.EdgeInsets.all(16),
29 | child: widgets.Text(
30 | column.title,
31 | style: const widgets.TextStyle(fontWeight: widgets.FontWeight.w500),
32 | ),
33 | );
34 | }).toList(),
35 | decoration: const widgets.BoxDecoration(
36 | border:
37 | widgets.Border(bottom: widgets.BorderSide(color: Colors.gray_4)),
38 | color: Colors.gray_3,
39 | ),
40 | );
41 |
42 | List rows = [];
43 | for (var i = 0; i < widget.dataSource.length; i++) {
44 | rows.add(
45 | widgets.TableRow(
46 | children: widget.columns.map((column) {
47 | return widgets.MouseRegion(
48 | child: widgets.GestureDetector(
49 | child: widgets.Container(
50 | padding: const widgets.EdgeInsets.all(16),
51 | child: _buildCell(widget.dataSource[i], column),
52 | ),
53 | ),
54 | onEnter: (_) => setState(() => hoveredRow = i),
55 | onExit: (_) => setState(() => hoveredRow = null),
56 | );
57 | }).toList(),
58 | decoration: widgets.BoxDecoration(
59 | border: const widgets.Border(
60 | bottom: widgets.BorderSide(color: Colors.gray_4)),
61 | color: i == hoveredRow ? Colors.gray_3 : null,
62 | ),
63 | ),
64 | );
65 | }
66 |
67 | Map widths = {};
68 | for (var i = 0; i < widget.columns.length; i++) {
69 | if (widget.columns[i].width != null) {
70 | widths[i] = widgets.FixedColumnWidth(widget.columns[i].width!);
71 | }
72 | }
73 |
74 | return widgets.Column(
75 | children: [
76 | widgets.Table(
77 | columnWidths: widths,
78 | children: [header],
79 | defaultVerticalAlignment: widgets.TableCellVerticalAlignment.middle,
80 | ),
81 | widgets.Table(
82 | columnWidths: widths,
83 | children: rows,
84 | defaultVerticalAlignment: widgets.TableCellVerticalAlignment.middle,
85 | ),
86 | ],
87 | );
88 | }
89 |
90 | widgets.Widget _buildCell(dynamic data, TableColumn column) {
91 | return column.render?.call(data) ??
92 | widgets.Text(
93 | column.dataIndex != null
94 | ? data.toJson()[column.dataIndex].toString()
95 | : '',
96 | );
97 | }
98 | }
99 |
100 | class TableColumn {
101 | const TableColumn({
102 | this.alignment = widgets.Alignment.centerLeft,
103 | this.colSpan,
104 | this.dataIndex,
105 | this.render,
106 | required this.title,
107 | this.width,
108 | });
109 |
110 | final widgets.Alignment alignment;
111 | final double? colSpan;
112 | final String? dataIndex;
113 | final widgets.Widget Function(dynamic record)? render;
114 | final String title;
115 | final double? width;
116 | }
117 |
--------------------------------------------------------------------------------
/lib/src/widget/tabs.dart:
--------------------------------------------------------------------------------
1 | import 'package:ant_design_flutter/src/enum/placement.dart';
2 | import 'package:ant_design_flutter/src/enum/size.dart';
3 | import 'package:ant_design_flutter/src/style/color.dart';
4 | import 'package:flutter/widgets.dart';
5 |
6 | class Tabs extends StatefulWidget {
7 | const Tabs({
8 | Key? key,
9 | this.addIcon,
10 | this.animated = true,
11 | this.centered = false,
12 | required this.children,
13 | this.controller,
14 | this.hideAdd = false,
15 | this.moreIcon,
16 | this.renderTabBar,
17 | this.size = Size.middle,
18 | this.tabBarExtraContent,
19 | this.tabBarGutter,
20 | this.tabPosition = Placement.top,
21 | this.destroyInactiveTab = false,
22 | this.type = TabsType.line,
23 | this.onChange,
24 | this.onEdit,
25 | this.onTabClick,
26 | this.onTabScroll,
27 | }) : super(key: key);
28 |
29 | final Widget? addIcon;
30 | final bool animated;
31 | final bool centered;
32 | final List children;
33 | final TabsController? controller;
34 | final bool hideAdd;
35 | final Widget? moreIcon;
36 | final Widget Function()? renderTabBar;
37 | final Size size;
38 | final Widget? tabBarExtraContent;
39 | final double? tabBarGutter;
40 | final Placement tabPosition;
41 | final bool destroyInactiveTab;
42 | final TabsType type;
43 | final void Function(String activeKey)? onChange;
44 | final void Function()? onEdit;
45 | final void Function(String key)? onTabClick;
46 | final void Function()? onTabScroll;
47 |
48 | @override
49 | State createState() => _TabsState();
50 | }
51 |
52 | class _TabsState extends State {
53 | String? activeKey;
54 |
55 | @override
56 | void initState() {
57 | super.initState();
58 | setState(() {
59 | activeKey = widget.controller?.activeKey ?? widget.children.first.name;
60 | });
61 | }
62 |
63 | @override
64 | Widget build(BuildContext context) {
65 | Widget header = Container(
66 | decoration: const BoxDecoration(
67 | border: Border(bottom: BorderSide(color: Colors.gray_3)),
68 | ),
69 | margin: const EdgeInsets.only(bottom: 16),
70 | child: Row(
71 | children: widget.children
72 | .map((child) => _TabHeader(
73 | disabled: child.disabled, name: child.name, tab: child.tab))
74 | .toList(),
75 | ),
76 | );
77 |
78 | return _TabsInhertedWidget(
79 | activeKey: activeKey,
80 | child: Column(
81 | crossAxisAlignment: CrossAxisAlignment.start,
82 | children: [
83 | header,
84 | Stack(
85 | children: widget.children
86 | .map((child) =>
87 | Visibility(visible: child.name == activeKey, child: child))
88 | .toList(),
89 | ),
90 | ],
91 | ),
92 | onClick: (name) => setState(() => activeKey = name),
93 | );
94 | }
95 | }
96 |
97 | class _TabHeader extends StatefulWidget {
98 | const _TabHeader(
99 | {Key? key, required this.disabled, required this.name, required this.tab})
100 | : super(key: key);
101 |
102 | final bool disabled;
103 | final String name;
104 | final Widget tab;
105 |
106 | @override
107 | State<_TabHeader> createState() => __TabHeaderState();
108 | }
109 |
110 | class __TabHeaderState extends State<_TabHeader> {
111 | bool hovered = false;
112 |
113 | @override
114 | Widget build(BuildContext context) {
115 | var activeKey = _TabsInhertedWidget.of(context)!.activeKey;
116 |
117 | return MouseRegion(
118 | cursor: widget.disabled
119 | ? SystemMouseCursors.forbidden
120 | : SystemMouseCursors.click,
121 | onEnter: (_) => setState(() => hovered = true),
122 | onExit: (_) => setState(() => hovered = false),
123 | child: GestureDetector(
124 | onTap: _handleTap,
125 | child: Container(
126 | decoration: BoxDecoration(
127 | border: Border(
128 | bottom: BorderSide(
129 | color: widget.name == activeKey ? Colors.blue_6 : Colors.white,
130 | width: 2,
131 | ),
132 | ),
133 | ),
134 | child: Padding(
135 | padding: const EdgeInsets.all(12),
136 | child: DefaultTextStyle.merge(
137 | child: widget.tab,
138 | style: TextStyle(
139 | color: widget.disabled
140 | ? Colors.gray_3
141 | : widget.name == activeKey
142 | ? Colors.blue_6
143 | : null,
144 | ),
145 | ),
146 | ),
147 | ),
148 | ),
149 | );
150 | }
151 |
152 | void _handleTap() {
153 | var onClick = _TabsInhertedWidget.of(context)!.onClick;
154 | if (!widget.disabled) {
155 | onClick(widget.name);
156 | }
157 | }
158 | }
159 |
160 | class _TabsInhertedWidget extends InheritedWidget {
161 | final String? activeKey;
162 | final void Function(String name) onClick;
163 |
164 | const _TabsInhertedWidget(
165 | {required this.activeKey, required Widget child, required this.onClick})
166 | : super(child: child);
167 |
168 | static _TabsInhertedWidget? of(BuildContext context) {
169 | return context.dependOnInheritedWidgetOfExactType<_TabsInhertedWidget>();
170 | }
171 |
172 | @override
173 | bool updateShouldNotify(_TabsInhertedWidget oldWidget) {
174 | return oldWidget.activeKey != activeKey;
175 | }
176 | }
177 |
178 | class TabPane extends StatelessWidget {
179 | const TabPane({
180 | Key? key,
181 | this.child,
182 | this.closeIcon,
183 | this.disabled = false,
184 | this.forceRender = false,
185 | required this.name,
186 | required this.tab,
187 | }) : super(key: key);
188 |
189 | final Widget? child;
190 | final Widget? closeIcon;
191 | final bool disabled;
192 | final bool forceRender;
193 | final String name;
194 | final Widget tab;
195 |
196 | @override
197 | Widget build(BuildContext context) {
198 | return Container(
199 | child: child,
200 | );
201 | }
202 | }
203 |
204 | class TabsController extends ChangeNotifier {
205 | String? activeKey;
206 | }
207 |
208 | enum TabsType { line, card, editableCard }
209 |
--------------------------------------------------------------------------------
/lib/src/widget/tag.dart:
--------------------------------------------------------------------------------
1 | import 'package:ant_design_flutter/src/style/color.dart';
2 | import 'package:flutter/widgets.dart';
3 |
4 | class Tag extends StatefulWidget {
5 | const Tag({
6 | Key? key,
7 | required this.child,
8 | this.closable = false,
9 | this.closeIcon,
10 | this.color,
11 | this.icon,
12 | this.onClose,
13 | this.visible = true,
14 | }) : super(key: key);
15 |
16 | final Widget child;
17 | final bool closable;
18 | final Widget? closeIcon;
19 | final Color? color;
20 | final Widget? icon;
21 | final void Function()? onClose;
22 | final bool visible;
23 |
24 | @override
25 | State createState() => _TagState();
26 | }
27 |
28 | class _TagState extends State {
29 | @override
30 | Widget build(BuildContext context) {
31 | return DefaultTextStyle.merge(
32 | child: Container(
33 | decoration: BoxDecoration(
34 | border: Border.all(color: widget.color ?? Colors.gray_5),
35 | borderRadius: BorderRadius.circular(2),
36 | color: widget.color ?? Colors.gray_2,
37 | ),
38 | padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
39 | child: widget.child,
40 | ),
41 | style: const TextStyle(fontSize: 12),
42 | );
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/lib/src/widget/time_picker.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/time_picker.dart
--------------------------------------------------------------------------------
/lib/src/widget/tooltip.dart:
--------------------------------------------------------------------------------
1 | import 'dart:math';
2 |
3 | import 'package:ant_design_flutter/src/enum/placement.dart';
4 | import 'package:ant_design_flutter/src/enum/trigger.dart';
5 | import 'package:ant_design_flutter/src/style/color.dart';
6 | import 'package:flutter/gestures.dart';
7 | import 'package:flutter/material.dart' show Material;
8 | import 'package:flutter/widgets.dart';
9 |
10 | class Tooltip extends StatefulWidget {
11 | const Tooltip({
12 | Key? key,
13 | required this.child,
14 | this.placement = Placement.top,
15 | required this.label,
16 | this.trigger = Trigger.hover,
17 | }) : super(key: key);
18 |
19 | final Widget child;
20 | final Placement placement;
21 | final String label;
22 | final Trigger trigger;
23 |
24 | @override
25 | State createState() => _TooltipState();
26 | }
27 |
28 | class _TooltipState extends State {
29 | bool hovered = false;
30 | bool inserted = false;
31 | LayerLink link = LayerLink();
32 | late OverlayEntry entry;
33 |
34 | @override
35 | void initState() {
36 | super.initState();
37 | }
38 |
39 | @override
40 | Widget build(BuildContext context) {
41 | return MouseRegion(
42 | onEnter: _handleEnter,
43 | onExit: _handleExit,
44 | child: CompositedTransformTarget(link: link, child: widget.child),
45 | );
46 | }
47 |
48 | void updateOverlayEntry() {
49 | entry.remove();
50 | var size = context.size;
51 | entry = OverlayEntry(
52 | builder: (context) => Positioned(
53 | height: 38,
54 | child: CompositedTransformFollower(
55 | followerAnchor: Alignment.bottomCenter,
56 | link: link,
57 | offset: Offset(0, -1 * size!.height),
58 | showWhenUnlinked: false,
59 | targetAnchor: Alignment.topCenter,
60 | child: Material(
61 | elevation: 4,
62 | child: _TooltipOverlayEntry(label: widget.label),
63 | ),
64 | ),
65 | ),
66 | );
67 | Overlay.of(context).insert(entry);
68 | }
69 |
70 | void _handleEnter(PointerEnterEvent event) {
71 | var size = context.size;
72 | entry = OverlayEntry(
73 | builder: (context) => Positioned(
74 | height: 38,
75 | child: CompositedTransformFollower(
76 | followerAnchor: Alignment.bottomCenter,
77 | link: link,
78 | offset: Offset(0, -1 * size!.height),
79 | showWhenUnlinked: false,
80 | targetAnchor: Alignment.topCenter,
81 | child: Material(
82 | elevation: 4,
83 | child: _TooltipOverlayEntry(label: widget.label),
84 | ),
85 | ),
86 | ),
87 | );
88 | Overlay.of(context).insert(entry);
89 | }
90 |
91 | void _handleExit(PointerExitEvent event) {
92 | entry.remove();
93 | }
94 | }
95 |
96 | class _TooltipOverlayEntry extends StatelessWidget {
97 | const _TooltipOverlayEntry({Key? key, required this.label}) : super(key: key);
98 |
99 | final String label;
100 |
101 | @override
102 | Widget build(BuildContext context) {
103 | return Stack(
104 | alignment: AlignmentDirectional.bottomCenter,
105 | clipBehavior: Clip.none,
106 | children: [
107 | Positioned(
108 | bottom: -4,
109 | child: Transform.rotate(
110 | angle: pi / 4,
111 | child: Container(
112 | decoration: const BoxDecoration(
113 | borderRadius: BorderRadius.only(
114 | bottomRight: Radius.circular(2),
115 | ),
116 | color: Colors.gray_10,
117 | ),
118 | height: 8,
119 | width: 8,
120 | ),
121 | ),
122 | ),
123 | Container(
124 | alignment: AlignmentDirectional.center,
125 | decoration: BoxDecoration(
126 | borderRadius: BorderRadius.circular(2),
127 | color: Colors.gray_10,
128 | ),
129 | padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 12),
130 | child: Text(
131 | label,
132 | style: const TextStyle(
133 | color: Colors.white,
134 | fontSize: 14,
135 | height: 1,
136 | ),
137 | ),
138 | ),
139 | ],
140 | );
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/lib/src/widget/tour.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/tour.dart
--------------------------------------------------------------------------------
/lib/src/widget/transfer.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/transfer.dart
--------------------------------------------------------------------------------
/lib/src/widget/tree.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/tree.dart
--------------------------------------------------------------------------------
/lib/src/widget/tree_select.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/tree_select.dart
--------------------------------------------------------------------------------
/lib/src/widget/typography.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/widgets.dart';
2 |
3 | class TypographyText extends StatefulWidget {
4 | const TypographyText(
5 | this.text, {
6 | Key? key,
7 | this.code = false,
8 | this.copyable,
9 | this.delete = false,
10 | this.disable = false,
11 | this.editable,
12 | this.ellipsis,
13 | this.keyboard = false,
14 | this.mark = false,
15 | this.onClick,
16 | this.strong = false,
17 | this.italic = false,
18 | this.type = TypographyType.secondary,
19 | this.underline = false,
20 | }) : super(key: key);
21 |
22 | final bool code;
23 | final TypographyCopyable? copyable;
24 | final bool delete;
25 | final bool disable;
26 | final TypographyEditable? editable;
27 | final TypographyEllipsis? ellipsis;
28 | final bool keyboard;
29 | final bool mark;
30 | final void Function()? onClick;
31 | final bool strong;
32 | final bool italic;
33 | final String text;
34 | final TypographyType type;
35 | final bool underline;
36 |
37 | @override
38 | State createState() => _TypographyTextState();
39 | }
40 |
41 | class _TypographyTextState extends State {
42 | @override
43 | Widget build(BuildContext context) {
44 | return Container();
45 | }
46 | }
47 |
48 | class TypographyTitle extends StatefulWidget {
49 | const TypographyTitle(
50 | this.title, {
51 | Key? key,
52 | this.code = false,
53 | this.copyable,
54 | this.delete = false,
55 | this.disable = false,
56 | this.editable,
57 | this.ellipsis,
58 | this.level = 1,
59 | this.mark = false,
60 | this.onClick,
61 | this.strong = false,
62 | this.italic = false,
63 | this.type = TypographyType.secondary,
64 | this.underline = false,
65 | }) : super(key: key);
66 |
67 | final bool code;
68 | final TypographyCopyable? copyable;
69 | final bool delete;
70 | final bool disable;
71 | final TypographyEditable? editable;
72 | final TypographyEllipsis? ellipsis;
73 | final int level;
74 | final bool mark;
75 | final void Function()? onClick;
76 | final bool strong;
77 | final bool italic;
78 | final String title;
79 | final TypographyType type;
80 | final bool underline;
81 |
82 | @override
83 | State createState() => _TypographyTitleState();
84 | }
85 |
86 | class _TypographyTitleState extends State {
87 | @override
88 | Widget build(BuildContext context) {
89 | return Padding(
90 | padding: const EdgeInsets.only(top: 8, bottom: 20),
91 | child: Text(
92 | widget.title,
93 | style: TextStyle(
94 | fontSize: _calculateFontSize(),
95 | fontWeight: FontWeight.w500,
96 | ),
97 | ),
98 | );
99 | }
100 |
101 | double _calculateFontSize() {
102 | List sizes = [38, 30, 24, 20, 16];
103 | return sizes[widget.level - 1];
104 | }
105 | }
106 |
107 | class TypographyParagraph extends StatefulWidget {
108 | const TypographyParagraph(
109 | this.paragraph, {
110 | Key? key,
111 | this.code = false,
112 | this.copyable,
113 | this.delete = false,
114 | this.disable = false,
115 | this.editable,
116 | this.ellipsis,
117 | this.keyboard = false,
118 | this.mark = false,
119 | this.onClick,
120 | this.strong = false,
121 | this.italic = false,
122 | this.type = TypographyType.secondary,
123 | this.underline = false,
124 | }) : super(key: key);
125 |
126 | final bool code;
127 | final TypographyCopyable? copyable;
128 | final bool delete;
129 | final bool disable;
130 | final TypographyEditable? editable;
131 | final TypographyEllipsis? ellipsis;
132 | final bool keyboard;
133 | final bool mark;
134 | final void Function()? onClick;
135 | final String paragraph;
136 | final bool strong;
137 | final bool italic;
138 | final TypographyType type;
139 | final bool underline;
140 |
141 | @override
142 | State createState() => _TypographyParagraphState();
143 | }
144 |
145 | class _TypographyParagraphState extends State {
146 | @override
147 | Widget build(BuildContext context) {
148 | return Padding(
149 | padding: const EdgeInsets.only(bottom: 14),
150 | child: Text(widget.paragraph),
151 | );
152 | }
153 | }
154 |
155 | class TypographyCopyable {
156 | TypographyCopyable({
157 | this.icon,
158 | required this.text,
159 | this.tooltips,
160 | required this.onCopy,
161 | }) : assert(icon == null || icon.length == 2),
162 | assert(tooltips == null || tooltips.length == 2);
163 |
164 | List? icon;
165 | String text;
166 | List? tooltips;
167 | void Function() onCopy;
168 | }
169 |
170 | class TypographyEditable {
171 | TypographyEditable({
172 | this.autoSize,
173 | this.editing = false,
174 | this.icon,
175 | this.maxLength,
176 | this.tooltip,
177 | this.onCancel,
178 | this.onChange,
179 | this.onEnd,
180 | this.onStart,
181 | this.triggerType = TypographyEditableTriggerType.icon,
182 | this.enterIcon,
183 | });
184 |
185 | TypographyAutoSize? autoSize;
186 | bool editing;
187 | Widget? icon;
188 | int? maxLength;
189 | Widget? tooltip;
190 | void Function()? onCancel;
191 | void Function()? onChange;
192 | void Function()? onEnd;
193 | void Function()? onStart;
194 | TypographyEditableTriggerType triggerType;
195 | Widget? enterIcon;
196 | }
197 |
198 | class TypographyAutoSize {
199 | TypographyAutoSize({
200 | required this.minRows,
201 | required this.maxRows,
202 | });
203 |
204 | int minRows;
205 | int maxRows;
206 | }
207 |
208 | class TypographyEllipsis {
209 | TypographyEllipsis({
210 | this.expandable = false,
211 | required this.rows,
212 | this.suffix,
213 | this.symbol,
214 | this.tooltip,
215 | this.onEllipsis,
216 | this.onExpand,
217 | });
218 |
219 | bool expandable;
220 | int rows;
221 | String? suffix;
222 | Widget? symbol;
223 | Widget? tooltip;
224 | void Function(TypographyEllipsis ellipsis)? onEllipsis;
225 | void Function()? onExpand;
226 | }
227 |
228 | enum TypographyType { secondary, success, warning, danger }
229 |
230 | enum TypographyEditableTriggerType { icon, text, both }
231 |
--------------------------------------------------------------------------------
/lib/src/widget/upload.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/upload.dart
--------------------------------------------------------------------------------
/lib/src/widget/watermark.dart:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CalsRanna/ant_design_flutter/719d321fd738d81e73da59375ee91b8562e6ceae/lib/src/widget/watermark.dart
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: ant_design_flutter
2 | description: A Flutter UI framework designed for web / pc application, contains some high quality widgets.
3 | version: 0.0.1+5
4 | homepage: https://doc.antdf.xyz
5 | repository: https://github.com/CalsRanna/ant_design_flutter
6 |
7 | environment:
8 | sdk: ">=3.0.3 <4.0.0"
9 | flutter: ">=1.17.0"
10 |
11 | dependencies:
12 | dotted_border: ^2.0.0+2
13 | flutter:
14 | sdk: flutter
15 | flutter_spinkit: ^5.1.0
16 |
17 | dev_dependencies:
18 | flutter_test:
19 | sdk: flutter
20 | flutter_lints: ^2.0.1
21 |
22 | flutter:
23 |
--------------------------------------------------------------------------------
/test/antdf_test.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_test/flutter_test.dart';
2 |
3 | import 'package:ant_design_flutter/ant_design_flutter.dart';
4 |
5 | void main() {
6 | test('adds one to input values', () {
7 | var app = const AntApp();
8 | assert(app.runtimeType == AntApp);
9 | });
10 | }
11 |
--------------------------------------------------------------------------------