基础库
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.
 
 
 
 
 

247 line
6.9 KiB

  1. part of let_log;
  2. class LogWidget extends StatefulWidget {
  3. const LogWidget({Key key}) : super(key: key);
  4. @override
  5. _LogWidgetState createState() => _LogWidgetState();
  6. }
  7. class _LogWidgetState extends State<LogWidget> {
  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. _buildTools(),
  34. Expanded(
  35. child: ValueListenableBuilder<int>(
  36. valueListenable: _Log.length,
  37. builder: (context, value, child) {
  38. List<_Log> logs = _Log.list;
  39. if (_selectTypes.length < 4 || _keyword.isNotEmpty) {
  40. logs = _Log.list.where((test) {
  41. return _selectTypes.contains(test.type) &&
  42. test.contains(_keyword);
  43. }).toList();
  44. }
  45. final len = logs.length;
  46. return ListView.separated(
  47. itemBuilder: (context, index) {
  48. final item = Logger.config.reverse
  49. ? logs[len - index - 1]
  50. : logs[index];
  51. final color = _getColor(item.type, context);
  52. return _buildItem(item, color);
  53. },
  54. itemCount: len,
  55. controller: _scrollController,
  56. separatorBuilder: (context, index) {
  57. return const Divider(
  58. height: 10,
  59. thickness: 0.5,
  60. color: Color(0xFFE0E0E0),
  61. );
  62. },
  63. );
  64. },
  65. ),
  66. ),
  67. ],
  68. ),
  69. floatingActionButton: FloatingActionButton(
  70. onPressed: () {
  71. if (_goDown) {
  72. _scrollController.animateTo(
  73. _scrollController.position.maxScrollExtent * 2,
  74. curve: Curves.easeOut,
  75. duration: const Duration(milliseconds: 300),
  76. );
  77. } else {
  78. _scrollController.animateTo(
  79. 0,
  80. curve: Curves.easeOut,
  81. duration: const Duration(milliseconds: 300),
  82. );
  83. }
  84. _goDown = !_goDown;
  85. setState(() {});
  86. },
  87. mini: true,
  88. child: Icon(
  89. _goDown ? Icons.arrow_downward : Icons.arrow_upward,
  90. ),
  91. ),
  92. );
  93. }
  94. Widget _buildItem(_Log item, Color color) {
  95. return InkWell(
  96. onTap: () {
  97. final ClipboardData data = ClipboardData(text: item.toString());
  98. Clipboard.setData(data);
  99. showDialog(
  100. context: context,
  101. barrierDismissible: true,
  102. builder: (context) {
  103. return const Center(
  104. child: Material(
  105. color: Colors.transparent,
  106. child: Text(
  107. "copy success!",
  108. style: TextStyle(color: Colors.white, fontSize: 30),
  109. ),
  110. ),
  111. );
  112. },
  113. );
  114. },
  115. child: Padding(
  116. padding: const EdgeInsets.fromLTRB(16, 8, 16, 8),
  117. child: Column(
  118. crossAxisAlignment: CrossAxisAlignment.start,
  119. children: [
  120. Text(
  121. "${item.tabName} ${item.message} (${item.start.hour}:${item.start.minute}:${item.start.second}:${item.start.millisecond})",
  122. style: TextStyle(fontSize: 16, color: color),
  123. ),
  124. if (item.detail != null)
  125. Padding(
  126. padding: const EdgeInsets.only(top: 8),
  127. child: Text(
  128. item.detail,
  129. style: TextStyle(fontSize: 14, color: color),
  130. overflow: TextOverflow.ellipsis,
  131. maxLines: 20,
  132. ),
  133. )
  134. ],
  135. ),
  136. ),
  137. );
  138. }
  139. Color _getColor(_Type type, BuildContext context) {
  140. switch (type) {
  141. case _Type.debug:
  142. return Colors.blue;
  143. case _Type.warn:
  144. return const Color(0xFFF57F17);
  145. case _Type.error:
  146. return Colors.red;
  147. default:
  148. return Theme.of(context).textTheme.body1.color;
  149. }
  150. }
  151. final List<_Type> _selectTypes = [
  152. _Type.log,
  153. _Type.debug,
  154. _Type.warn,
  155. _Type.error
  156. ];
  157. Widget _buildTools() {
  158. final List<ChoiceChip> arr = [];
  159. _Type.values.forEach((f) {
  160. arr.add(
  161. ChoiceChip(
  162. label: Text(
  163. _getTabName(f.index),
  164. style: const TextStyle(fontSize: 14),
  165. ),
  166. selectedColor: const Color(0xFFCBE2F6),
  167. selected: _selectTypes.contains(f),
  168. onSelected: (value) {
  169. _selectTypes.contains(f)
  170. ? _selectTypes.remove(f)
  171. : _selectTypes.add(f);
  172. setState(() {});
  173. },
  174. ),
  175. );
  176. });
  177. return Padding(
  178. padding: const EdgeInsets.fromLTRB(16, 5, 0, 5),
  179. child: AnimatedCrossFade(
  180. crossFadeState:
  181. _showSearch ? CrossFadeState.showSecond : CrossFadeState.showFirst,
  182. duration: const Duration(milliseconds: 300),
  183. firstChild: Row(
  184. children: [
  185. Expanded(
  186. child: Wrap(
  187. spacing: 5,
  188. children: arr,
  189. ),
  190. ),
  191. const IconButton(
  192. icon: Icon(Icons.clear),
  193. onPressed: _Log.clear,
  194. ),
  195. IconButton(
  196. icon: _keyword.isEmpty
  197. ? const Icon(Icons.search)
  198. : const Icon(Icons.filter_1),
  199. onPressed: () {
  200. _showSearch = true;
  201. setState(() {});
  202. _focusNode.requestFocus();
  203. },
  204. ),
  205. ],
  206. ),
  207. secondChild: Row(
  208. children: [
  209. Expanded(
  210. child: SizedBox(
  211. height: 36,
  212. child: TextField(
  213. decoration: const InputDecoration(
  214. border: OutlineInputBorder(),
  215. contentPadding: EdgeInsets.all(6),
  216. ),
  217. controller: _textController,
  218. focusNode: _focusNode,
  219. ),
  220. ),
  221. ),
  222. IconButton(
  223. icon: const Icon(Icons.search),
  224. onPressed: () {
  225. _showSearch = false;
  226. _keyword = _textController.text;
  227. setState(() {});
  228. },
  229. ),
  230. ],
  231. ),
  232. ),
  233. );
  234. }
  235. }