基础库
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 
 
 

334 Zeilen
11 KiB

  1. part of let_log;
  2. class NetWidget extends StatefulWidget {
  3. const NetWidget({Key key}) : super(key: key);
  4. @override
  5. _NetWidgetState createState() => _NetWidgetState();
  6. }
  7. class _NetWidgetState extends State<NetWidget> {
  8. bool _showSearch = false;
  9. String _keyword = "";
  10. TextEditingController _textController;
  11. ScrollController _scrollController;
  12. FocusNode _focusNode;
  13. bool _goDown = true;
  14. @override
  15. void initState() {
  16. _textController = TextEditingController(text: _keyword);
  17. _scrollController = ScrollController();
  18. _focusNode = FocusNode();
  19. super.initState();
  20. }
  21. @override
  22. void dispose() {
  23. _textController.dispose();
  24. _scrollController.dispose();
  25. super.dispose();
  26. }
  27. @override
  28. Widget build(BuildContext context) {
  29. return Scaffold(
  30. body: Column(
  31. crossAxisAlignment: CrossAxisAlignment.start,
  32. children: <Widget>[
  33. ValueListenableBuilder<int>(
  34. valueListenable: _Net.typeLength,
  35. builder: (context, value, child) {
  36. return _buildTools();
  37. },
  38. ),
  39. Expanded(
  40. child: ValueListenableBuilder<int>(
  41. valueListenable: _Net.length,
  42. builder: (context, value, child) {
  43. List<_Net> logs = _Net.list;
  44. if (!_selectTypes.contains(_Net.all)) {
  45. logs = _Net.list.where((test) {
  46. return _selectTypes.contains(test.type) &&
  47. test.contains(_keyword);
  48. }).toList();
  49. } else if (_keyword.isNotEmpty) {
  50. logs = _Net.list.where((test) {
  51. return test.contains(_keyword);
  52. }).toList();
  53. }
  54. final len = logs.length;
  55. return ListView.separated(
  56. itemBuilder: (context, index) {
  57. final item = Logger.config.reverse
  58. ? logs[len - index - 1]
  59. : logs[index];
  60. return _buildItem(item, context);
  61. },
  62. itemCount: len,
  63. controller: _scrollController,
  64. reverse: Logger.config.reverse,
  65. separatorBuilder: (context, index) {
  66. return const Divider(
  67. height: 10,
  68. thickness: 0.5,
  69. color: Color(0xFFE0E0E0),
  70. );
  71. },
  72. );
  73. },
  74. ),
  75. ),
  76. ],
  77. ),
  78. floatingActionButton: FloatingActionButton(
  79. onPressed: () {
  80. if (_goDown) {
  81. _scrollController.animateTo(
  82. _scrollController.position.maxScrollExtent * 2,
  83. curve: Curves.easeOut,
  84. duration: const Duration(milliseconds: 300),
  85. );
  86. } else {
  87. _scrollController.animateTo(
  88. 0,
  89. curve: Curves.easeOut,
  90. duration: const Duration(milliseconds: 300),
  91. );
  92. }
  93. _goDown = !_goDown;
  94. setState(() {});
  95. },
  96. mini: true,
  97. child: Icon(
  98. _goDown ? Icons.arrow_downward : Icons.arrow_upward,
  99. ),
  100. ),
  101. );
  102. }
  103. Widget _buildItem(_Net item, context) {
  104. final color = _getColor(item.status);
  105. return InkWell(
  106. onTap: () {
  107. item.showDetail = !item.showDetail;
  108. setState(() {});
  109. },
  110. child: Padding(
  111. padding: const EdgeInsets.fromLTRB(16, 8, 16, 0),
  112. child: Row(
  113. children: [
  114. Expanded(
  115. child: Column(
  116. crossAxisAlignment: CrossAxisAlignment.start,
  117. children: [
  118. Text(
  119. "[${item.type}] ${item.api}",
  120. style: const TextStyle(fontSize: 16),
  121. ),
  122. // if (item.showDetail)
  123. Visibility(
  124. visible: item.showDetail,
  125. child: Padding(
  126. padding: const EdgeInsets.only(top: 8),
  127. child: Text(
  128. "Request: ${item.req ?? ""}",
  129. maxLines: 100,
  130. overflow: TextOverflow.ellipsis,
  131. style: const TextStyle(fontSize: 14),
  132. ),
  133. ),
  134. ),
  135. // if (item.showDetail)
  136. Visibility(
  137. visible: item.showDetail,
  138. child: Padding(
  139. padding: const EdgeInsets.only(top: 8),
  140. child: Text(
  141. "Response: ${item.res ?? ""}",
  142. maxLines: 100,
  143. overflow: TextOverflow.ellipsis,
  144. style: const TextStyle(fontSize: 14),
  145. ),
  146. ),
  147. ),
  148. // if (item.showDetail && item.headers != null)
  149. Visibility(
  150. visible: (item.showDetail && item.headers != null),
  151. child: Padding(
  152. padding: const EdgeInsets.only(top: 8),
  153. child: Text(
  154. "Headers: ${item.headers ?? ""}",
  155. maxLines: 100,
  156. overflow: TextOverflow.ellipsis,
  157. style: const TextStyle(fontSize: 14),
  158. ),
  159. ),
  160. ),
  161. Padding(
  162. padding: const EdgeInsets.only(top: 8, bottom: 8),
  163. child: Row(
  164. children: [
  165. SizedBox(
  166. width: 120,
  167. child: Text(
  168. "${item.start.hour}:${item.start.minute}:${item.start.second}:${item.start.millisecond}",
  169. style: const TextStyle(fontSize: 14),
  170. maxLines: 1,
  171. ),
  172. ),
  173. SizedBox(
  174. width: 100,
  175. child: Text(
  176. "${item.spend ?? "0"} ms",
  177. style: const TextStyle(fontSize: 14),
  178. overflow: TextOverflow.visible,
  179. maxLines: 1,
  180. ),
  181. ),
  182. Text(
  183. "${item.getReqSize()}/${item.getResSize()}B",
  184. style: const TextStyle(fontSize: 14),
  185. overflow: TextOverflow.visible,
  186. maxLines: 1,
  187. ),
  188. ],
  189. ),
  190. )
  191. ],
  192. ),
  193. ),
  194. InkWell(
  195. onTap: () {
  196. final ClipboardData data = ClipboardData(text: item.toString());
  197. Clipboard.setData(data);
  198. showDialog(
  199. context: context,
  200. barrierDismissible: true,
  201. builder: (context) {
  202. return const Center(
  203. child: Material(
  204. color: Colors.transparent,
  205. child: Text(
  206. "copy success!",
  207. style: TextStyle(color: Colors.white, fontSize: 30),
  208. ),
  209. ),
  210. );
  211. },
  212. );
  213. },
  214. child: Column(
  215. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  216. children: [
  217. Text(
  218. item.status.toString(),
  219. style: TextStyle(fontSize: 20, color: color),
  220. ),
  221. // if (item.showDetail)
  222. Visibility(
  223. visible: item.showDetail,
  224. child: const Text(
  225. "copy",
  226. style: TextStyle(fontSize: 16, color: Colors.blue),
  227. ),
  228. ),
  229. ],
  230. ),
  231. ),
  232. ],
  233. ),
  234. ),
  235. );
  236. }
  237. Color _getColor(int status) {
  238. if (status == 200 || status == 0) {
  239. return Colors.green;
  240. } else if (status < 200) {
  241. return Colors.blue;
  242. } else {
  243. return Colors.red;
  244. }
  245. }
  246. final List<String> _selectTypes = [_Net.all];
  247. Widget _buildTools() {
  248. final List<ChoiceChip> arr = [];
  249. _Net.types.forEach((f) {
  250. arr.add(
  251. ChoiceChip(
  252. label: Text(f, style: const TextStyle(fontSize: 14)),
  253. selectedColor: const Color(0xFFCBE2F6),
  254. selected: _selectTypes.contains(f),
  255. onSelected: (value) {
  256. _selectTypes.contains(f)
  257. ? _selectTypes.remove(f)
  258. : _selectTypes.add(f);
  259. setState(() {});
  260. },
  261. ),
  262. );
  263. });
  264. return Padding(
  265. padding: const EdgeInsets.fromLTRB(16, 5, 0, 5),
  266. child: AnimatedCrossFade(
  267. crossFadeState:
  268. _showSearch ? CrossFadeState.showSecond : CrossFadeState.showFirst,
  269. duration: const Duration(milliseconds: 300),
  270. firstChild: Row(
  271. children: [
  272. Expanded(
  273. child: Wrap(
  274. spacing: 5,
  275. children: arr,
  276. ),
  277. ),
  278. const IconButton(
  279. icon: Icon(Icons.clear),
  280. onPressed: _Net.clear,
  281. ),
  282. IconButton(
  283. icon: _keyword.isEmpty
  284. ? const Icon(Icons.search)
  285. : const Icon(Icons.filter_1),
  286. onPressed: () {
  287. _showSearch = true;
  288. setState(() {});
  289. _focusNode.requestFocus();
  290. },
  291. ),
  292. ],
  293. ),
  294. secondChild: Row(
  295. children: [
  296. Expanded(
  297. child: SizedBox(
  298. height: 36,
  299. child: TextField(
  300. decoration: const InputDecoration(
  301. border: OutlineInputBorder(),
  302. contentPadding: EdgeInsets.all(6),
  303. ),
  304. controller: _textController,
  305. focusNode: _focusNode,
  306. ),
  307. ),
  308. ),
  309. IconButton(
  310. icon: const Icon(Icons.search),
  311. onPressed: () {
  312. _showSearch = false;
  313. _keyword = _textController.text;
  314. setState(() {});
  315. },
  316. ),
  317. ],
  318. ),
  319. ),
  320. );
  321. }
  322. }