基础库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

322 lines
10 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. Padding(
  124. padding: const EdgeInsets.only(top: 8),
  125. child: Text(
  126. "Request: ${item.req ?? ""}",
  127. maxLines: 100,
  128. overflow: TextOverflow.ellipsis,
  129. style: const TextStyle(fontSize: 14),
  130. ),
  131. ),
  132. if (item.showDetail)
  133. Padding(
  134. padding: const EdgeInsets.only(top: 8),
  135. child: Text(
  136. "Response: ${item.res ?? ""}",
  137. maxLines: 100,
  138. overflow: TextOverflow.ellipsis,
  139. style: const TextStyle(fontSize: 14),
  140. ),
  141. ),
  142. if (item.showDetail && item.headers != null)
  143. Padding(
  144. padding: const EdgeInsets.only(top: 8),
  145. child: Text(
  146. "Headers: ${item.headers ?? ""}",
  147. maxLines: 100,
  148. overflow: TextOverflow.ellipsis,
  149. style: const TextStyle(fontSize: 14),
  150. ),
  151. ),
  152. Padding(
  153. padding: const EdgeInsets.only(top: 8, bottom: 8),
  154. child: Row(
  155. children: [
  156. SizedBox(
  157. width: 120,
  158. child: Text(
  159. "${item.start.hour}:${item.start.minute}:${item.start.second}:${item.start.millisecond}",
  160. style: const TextStyle(fontSize: 14),
  161. maxLines: 1,
  162. ),
  163. ),
  164. SizedBox(
  165. width: 100,
  166. child: Text(
  167. "${item.spend ?? "0"} ms",
  168. style: const TextStyle(fontSize: 14),
  169. overflow: TextOverflow.visible,
  170. maxLines: 1,
  171. ),
  172. ),
  173. Text(
  174. "${item.getReqSize()}/${item.getResSize()}B",
  175. style: const TextStyle(fontSize: 14),
  176. overflow: TextOverflow.visible,
  177. maxLines: 1,
  178. ),
  179. ],
  180. ),
  181. )
  182. ],
  183. ),
  184. ),
  185. InkWell(
  186. onTap: () {
  187. final ClipboardData data = ClipboardData(text: item.toString());
  188. Clipboard.setData(data);
  189. showDialog(
  190. context: context,
  191. barrierDismissible: true,
  192. builder: (context) {
  193. return const Center(
  194. child: Material(
  195. color: Colors.transparent,
  196. child: Text(
  197. "copy success!",
  198. style: TextStyle(color: Colors.white, fontSize: 30),
  199. ),
  200. ),
  201. );
  202. },
  203. );
  204. },
  205. child: Column(
  206. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  207. children: [
  208. Text(
  209. item.status.toString(),
  210. style: TextStyle(fontSize: 20, color: color),
  211. ),
  212. if (item.showDetail)
  213. const Text(
  214. "copy",
  215. style: TextStyle(fontSize: 16, color: Colors.blue),
  216. ),
  217. ],
  218. ),
  219. ),
  220. ],
  221. ),
  222. ),
  223. );
  224. }
  225. Color _getColor(int status) {
  226. if (status == 200 || status == 0) {
  227. return Colors.green;
  228. } else if (status < 200) {
  229. return Colors.blue;
  230. } else {
  231. return Colors.red;
  232. }
  233. }
  234. final List<String> _selectTypes = [_Net.all];
  235. Widget _buildTools() {
  236. final List<ChoiceChip> arr = [];
  237. _Net.types.forEach((f) {
  238. arr.add(
  239. ChoiceChip(
  240. label: Text(f, style: const TextStyle(fontSize: 14)),
  241. selectedColor: const Color(0xFFCBE2F6),
  242. selected: _selectTypes.contains(f),
  243. onSelected: (value) {
  244. _selectTypes.contains(f)
  245. ? _selectTypes.remove(f)
  246. : _selectTypes.add(f);
  247. setState(() {});
  248. },
  249. ),
  250. );
  251. });
  252. return Padding(
  253. padding: const EdgeInsets.fromLTRB(16, 5, 0, 5),
  254. child: AnimatedCrossFade(
  255. crossFadeState:
  256. _showSearch ? CrossFadeState.showSecond : CrossFadeState.showFirst,
  257. duration: const Duration(milliseconds: 300),
  258. firstChild: Row(
  259. children: [
  260. Expanded(
  261. child: Wrap(
  262. spacing: 5,
  263. children: arr,
  264. ),
  265. ),
  266. const IconButton(
  267. icon: Icon(Icons.clear),
  268. onPressed: _Net.clear,
  269. ),
  270. IconButton(
  271. icon: _keyword.isEmpty
  272. ? const Icon(Icons.search)
  273. : const Icon(Icons.filter_1),
  274. onPressed: () {
  275. _showSearch = true;
  276. setState(() {});
  277. _focusNode.requestFocus();
  278. },
  279. ),
  280. ],
  281. ),
  282. secondChild: Row(
  283. children: [
  284. Expanded(
  285. child: SizedBox(
  286. height: 36,
  287. child: TextField(
  288. decoration: const InputDecoration(
  289. border: OutlineInputBorder(),
  290. contentPadding: EdgeInsets.all(6),
  291. ),
  292. controller: _textController,
  293. focusNode: _focusNode,
  294. ),
  295. ),
  296. ),
  297. IconButton(
  298. icon: const Icon(Icons.search),
  299. onPressed: () {
  300. _showSearch = false;
  301. _keyword = _textController.text;
  302. setState(() {});
  303. },
  304. ),
  305. ],
  306. ),
  307. ),
  308. );
  309. }
  310. }