| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922 |
- import 'dart:convert';
- import 'package:archive/archive.dart';
- import 'package:flutter/material.dart';
- import 'package:get/get.dart';
- import 'package:dio/dio.dart' as dio;
- import 'package:nomo/config/theme/theme_extensions/theme_extension.dart';
- import '../../app/constants/keys.dart';
- import '../crypto.dart';
- import '../log/logger.dart';
- import 'simple_log_card.dart';
- import 'simple_api_card.dart';
- /// 简化版开发者工具 - 只包含控制台日志和API监控
- class IXDeveloperTools {
- static final IXDeveloperTools _instance = IXDeveloperTools._internal();
- factory IXDeveloperTools() => _instance;
- IXDeveloperTools._internal();
- final List<ConsoleLogEntry> _logs = [];
- final List<ApiRequestInfo> _apiRequests = [];
- static const int maxLogs = 1000;
- static const int maxApiRequests = 500;
- /// 添加控制台日志
- static void addLog(String message, String tag) {
- final entry = ConsoleLogEntry(
- timestamp: DateTime.now(),
- message: message,
- tag: tag,
- );
- _instance._logs.insert(0, entry);
- if (_instance._logs.length > maxLogs) {
- _instance._logs.removeRange(maxLogs, _instance._logs.length);
- }
- }
- /// 添加API请求信息
- static void addApiRequest(ApiRequestInfo request) {
- _instance._apiRequests.insert(0, request);
- if (_instance._apiRequests.length > maxApiRequests) {
- _instance._apiRequests.removeRange(
- maxApiRequests,
- _instance._apiRequests.length,
- );
- }
- }
- /// 获取所有日志
- static List<ConsoleLogEntry> get logs => List.unmodifiable(_instance._logs);
- /// 获取所有API请求
- static List<ApiRequestInfo> get apiRequests =>
- List.unmodifiable(_instance._apiRequests);
- /// 清除所有日志
- static void clearLogs() {
- _instance._logs.clear();
- }
- /// 清除所有API请求
- static void clearApiRequests() {
- _instance._apiRequests.clear();
- }
- /// 显示开发者工具
- static void show() {
- try {
- Get.to(
- () => const SimpleDeveloperToolsScreen(),
- transition: Transition.cupertino,
- );
- } catch (e) {
- log('IXDeveloperTools', 'Unable to open Developer Tools: $e');
- }
- }
- }
- /// 控制台日志条目
- class ConsoleLogEntry {
- final DateTime timestamp;
- final String message;
- final String tag;
- ConsoleLogEntry({
- required this.timestamp,
- required this.message,
- required this.tag,
- });
- String get formattedTime {
- return '${timestamp.hour.toString().padLeft(2, '0')}:'
- '${timestamp.minute.toString().padLeft(2, '0')}:'
- '${timestamp.second.toString().padLeft(2, '0')}.'
- '${timestamp.millisecond.toString().padLeft(3, '0')}';
- }
- }
- /// API请求信息
- class ApiRequestInfo {
- final String id;
- final DateTime timestamp;
- final String method;
- final String url;
- final Map<String, dynamic>? headers;
- final dynamic requestData;
- final int? statusCode;
- final dynamic responseData;
- final String? error;
- final Duration? duration;
- ApiRequestInfo({
- required this.id,
- required this.timestamp,
- required this.method,
- required this.url,
- this.headers,
- this.requestData,
- this.statusCode,
- this.responseData,
- this.error,
- this.duration,
- });
- String get statusText {
- if (error != null) return 'ERROR';
- if (statusCode == null) return 'PENDING';
- if (statusCode! >= 200 && statusCode! < 300) return 'SUCCESS';
- if (statusCode! >= 400) return 'ERROR';
- return 'UNKNOWN';
- }
- Color get statusColor {
- switch (statusText) {
- case 'SUCCESS':
- return Colors.green;
- case 'ERROR':
- return Colors.red;
- case 'PENDING':
- return Colors.orange;
- default:
- return Colors.grey;
- }
- }
- }
- /// 简化版API监控拦截器
- class SimpleApiMonitorInterceptor extends dio.Interceptor {
- final Map<String, DateTime> _requestStartTimes = {};
- @override
- void onRequest(
- dio.RequestOptions options,
- dio.RequestInterceptorHandler handler,
- ) {
- final requestId = _generateRequestId();
- _requestStartTimes[requestId] = DateTime.now();
- final request = ApiRequestInfo(
- id: requestId,
- timestamp: DateTime.now(),
- method: options.method,
- url: options.uri.toString(),
- headers: options.headers,
- requestData: options.data is FormData
- ? options.data.fields
- : _decryptData(options.data),
- );
- IXDeveloperTools.addApiRequest(request);
- handler.next(options);
- }
- @override
- void onResponse(
- dio.Response response,
- dio.ResponseInterceptorHandler handler,
- ) {
- final requestId = _findRequestId(response.requestOptions.uri.toString());
- if (requestId != null) {
- final startTime = _requestStartTimes.remove(requestId);
- final duration = startTime != null
- ? DateTime.now().difference(startTime)
- : null;
- final updatedRequest = ApiRequestInfo(
- id: requestId,
- timestamp: DateTime.now(),
- method: response.requestOptions.method,
- url: response.requestOptions.uri.toString(),
- headers: response.requestOptions.headers,
- requestData: response.requestOptions.data is FormData
- ? response.requestOptions.data.fields
- : _decryptData(response.requestOptions.data),
- statusCode: response.statusCode,
- responseData: _decryptData(response.data),
- duration: duration,
- );
- _updateApiRequest(updatedRequest);
- }
- handler.next(response);
- }
- @override
- void onError(dio.DioException err, dio.ErrorInterceptorHandler handler) {
- final requestId = _findRequestId(err.requestOptions.uri.toString());
- if (requestId != null) {
- final startTime = _requestStartTimes.remove(requestId);
- final duration = startTime != null
- ? DateTime.now().difference(startTime)
- : null;
- final updatedRequest = ApiRequestInfo(
- id: requestId,
- timestamp: DateTime.now(),
- method: err.requestOptions.method,
- url: err.requestOptions.uri.toString(),
- headers: err.requestOptions.headers,
- requestData: err.requestOptions.data is FormData
- ? err.requestOptions.data.fields
- : _decryptData(err.requestOptions.data),
- statusCode: err.response?.statusCode,
- error: err.message,
- duration: duration,
- );
- _updateApiRequest(updatedRequest);
- }
- handler.next(err);
- }
- dynamic _decryptData(dynamic encryptedData) {
- try {
- // 1. Base64 编码
- final base64Data = base64Encode(encryptedData);
- // 2. AES 解密
- final decryptedBytes = Crypto.decryptBytes(
- base64Data,
- Keys.aesKey,
- Keys.aesIv,
- );
- // 3. GZip 解压
- final gzipDecoder = GZipDecoder();
- final decompressedData = gzipDecoder.decodeBytes(decryptedBytes);
- // 4. UTF-8 解码
- final data = utf8.decode(decompressedData);
- // string to json
- return jsonDecode(data);
- } catch (e) {
- return encryptedData;
- }
- }
- String _generateRequestId() {
- return '${DateTime.now().millisecondsSinceEpoch}_${IXDeveloperTools.apiRequests.length}';
- }
- String? _findRequestId(String url) {
- try {
- final request = IXDeveloperTools.apiRequests.firstWhere(
- (r) => r.url == url && r.statusCode == null,
- );
- return request.id;
- } catch (e) {
- return null;
- }
- }
- void _updateApiRequest(ApiRequestInfo updatedRequest) {
- final requests = IXDeveloperTools._instance._apiRequests;
- final index = requests.indexWhere((r) => r.id == updatedRequest.id);
- if (index != -1) {
- requests[index] = updatedRequest;
- }
- }
- }
- class SimpleNoSignApiMonitorInterceptor extends dio.Interceptor {
- final Map<String, DateTime> _requestStartTimes = {};
- @override
- void onRequest(
- dio.RequestOptions options,
- dio.RequestInterceptorHandler handler,
- ) {
- final requestId = _generateRequestId();
- _requestStartTimes[requestId] = DateTime.now();
- final request = ApiRequestInfo(
- id: requestId,
- timestamp: DateTime.now(),
- method: options.method,
- url: options.uri.toString(),
- headers: options.headers,
- requestData: options.data,
- );
- IXDeveloperTools.addApiRequest(request);
- handler.next(options);
- }
- @override
- void onResponse(
- dio.Response response,
- dio.ResponseInterceptorHandler handler,
- ) {
- final requestId = _findRequestId(response.requestOptions.uri.toString());
- if (requestId != null) {
- final startTime = _requestStartTimes.remove(requestId);
- final duration = startTime != null
- ? DateTime.now().difference(startTime)
- : null;
- final updatedRequest = ApiRequestInfo(
- id: requestId,
- timestamp: DateTime.now(),
- method: response.requestOptions.method,
- url: response.requestOptions.uri.toString(),
- headers: response.requestOptions.headers,
- requestData: response.requestOptions.data,
- statusCode: response.statusCode,
- responseData: response.data,
- duration: duration,
- );
- _updateApiRequest(updatedRequest);
- }
- handler.next(response);
- }
- @override
- void onError(dio.DioException err, dio.ErrorInterceptorHandler handler) {
- final requestId = _findRequestId(err.requestOptions.uri.toString());
- if (requestId != null) {
- final startTime = _requestStartTimes.remove(requestId);
- final duration = startTime != null
- ? DateTime.now().difference(startTime)
- : null;
- final updatedRequest = ApiRequestInfo(
- id: requestId,
- timestamp: DateTime.now(),
- method: err.requestOptions.method,
- url: err.requestOptions.uri.toString(),
- headers: err.requestOptions.headers,
- requestData: err.requestOptions.data,
- statusCode: err.response?.statusCode,
- error: err.message,
- duration: duration,
- );
- _updateApiRequest(updatedRequest);
- }
- handler.next(err);
- }
- String _generateRequestId() {
- return '${DateTime.now().millisecondsSinceEpoch}_${IXDeveloperTools.apiRequests.length}';
- }
- String? _findRequestId(String url) {
- try {
- final request = IXDeveloperTools.apiRequests.firstWhere(
- (r) => r.url == url && r.statusCode == null,
- );
- return request.id;
- } catch (e) {
- return null;
- }
- }
- void _updateApiRequest(ApiRequestInfo updatedRequest) {
- final requests = IXDeveloperTools._instance._apiRequests;
- final index = requests.indexWhere((r) => r.id == updatedRequest.id);
- if (index != -1) {
- requests[index] = updatedRequest;
- }
- }
- }
- /// 简化版开发者工具主界面
- class SimpleDeveloperToolsScreen extends StatefulWidget {
- const SimpleDeveloperToolsScreen({super.key});
- @override
- State<SimpleDeveloperToolsScreen> createState() =>
- _SimpleDeveloperToolsScreenState();
- }
- class _SimpleDeveloperToolsScreenState extends State<SimpleDeveloperToolsScreen>
- with SingleTickerProviderStateMixin {
- late TabController _tabController;
- @override
- void initState() {
- super.initState();
- _tabController = TabController(length: 2, vsync: this);
- _tabController.index = 1;
- }
- @override
- void dispose() {
- _tabController.dispose();
- super.dispose();
- }
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- backgroundColor: Get.reactiveTheme.scaffoldBackgroundColor,
- appBar: AppBar(
- elevation: 0,
- iconTheme: IconThemeData(
- color: Get.reactiveTheme.textTheme.bodyLarge!.color,
- ),
- title: Text(
- '开发者工具',
- style: TextStyle(
- fontWeight: FontWeight.bold,
- fontSize: 18,
- color: Get.reactiveTheme.textTheme.bodyLarge!.color,
- ),
- ),
- bottom: PreferredSize(
- preferredSize: const Size.fromHeight(50),
- child: Container(
- margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
- decoration: BoxDecoration(
- color: Colors.grey[100],
- borderRadius: BorderRadius.circular(25),
- boxShadow: [
- BoxShadow(
- color: Colors.grey[300]!.withValues(alpha: 0.5),
- blurRadius: 4,
- offset: const Offset(0, 2),
- ),
- ],
- ),
- child: TabBar(
- controller: _tabController,
- indicator: BoxDecoration(
- gradient: LinearGradient(
- colors: [Colors.blue[500]!, Colors.purple[500]!],
- ),
- borderRadius: BorderRadius.circular(25),
- boxShadow: [
- BoxShadow(
- color: Colors.blue[200]!.withValues(alpha: 0.5),
- blurRadius: 6,
- offset: const Offset(0, 2),
- ),
- ],
- ),
- indicatorSize: TabBarIndicatorSize.tab,
- dividerColor: Colors.transparent,
- labelColor: Colors.white,
- unselectedLabelColor: Colors.grey[600],
- labelStyle: const TextStyle(
- fontWeight: FontWeight.bold,
- fontSize: 14,
- ),
- unselectedLabelStyle: const TextStyle(
- fontWeight: FontWeight.w500,
- fontSize: 14,
- ),
- tabs: const [
- Tab(
- child: Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- Icon(Icons.terminal, size: 18),
- SizedBox(width: 6),
- Text('控制台日志'),
- ],
- ),
- ),
- Tab(
- child: Row(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- Icon(Icons.network_check, size: 18),
- SizedBox(width: 6),
- Text('API监控'),
- ],
- ),
- ),
- ],
- ),
- ),
- ),
- ),
- body: Container(
- decoration: const BoxDecoration(
- gradient: LinearGradient(
- begin: Alignment.topCenter,
- end: Alignment.bottomCenter,
- colors: [Colors.grey, Colors.blue],
- ),
- ),
- child: TabBarView(
- controller: _tabController,
- children: const [SimpleConsoleLogTab(), SimpleApiMonitorTab()],
- ),
- ),
- );
- }
- }
- /// 简化版开发者工具对话框
- class SimpleDeveloperToolsDialog extends StatelessWidget {
- const SimpleDeveloperToolsDialog({super.key});
- @override
- Widget build(BuildContext context) {
- return Dialog(
- backgroundColor: Colors.transparent,
- elevation: 0,
- child: Container(
- width: Get.width * 0.95,
- height: Get.height * 0.9,
- decoration: BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.circular(20),
- boxShadow: [
- BoxShadow(
- color: Colors.black.withValues(alpha: 0.1),
- blurRadius: 20,
- offset: const Offset(0, 10),
- ),
- ],
- ),
- child: ClipRRect(
- borderRadius: BorderRadius.circular(20),
- child: const SimpleDeveloperToolsScreen(),
- ),
- ),
- );
- }
- }
- /// 简化版控制台日志标签页
- class SimpleConsoleLogTab extends StatefulWidget {
- const SimpleConsoleLogTab({super.key});
- @override
- State<SimpleConsoleLogTab> createState() => _SimpleConsoleLogTabState();
- }
- class _SimpleConsoleLogTabState extends State<SimpleConsoleLogTab> {
- final TextEditingController _searchController = TextEditingController();
- List<ConsoleLogEntry> _filteredLogs = [];
- @override
- void initState() {
- super.initState();
- _updateLogs();
- }
- void _updateLogs() {
- setState(() {
- final allLogs = IXDeveloperTools.logs;
- if (_searchController.text.isEmpty) {
- _filteredLogs = allLogs;
- } else {
- _filteredLogs = allLogs
- .where(
- (log) =>
- log.message.toLowerCase().contains(
- _searchController.text.toLowerCase(),
- ) ||
- log.tag.toLowerCase().contains(
- _searchController.text.toLowerCase(),
- ),
- )
- .toList();
- }
- });
- }
- @override
- Widget build(BuildContext context) {
- return Column(
- children: [
- // 搜索和操作栏
- Container(
- margin: const EdgeInsets.all(16),
- padding: const EdgeInsets.all(16),
- decoration: BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.circular(16),
- boxShadow: [
- BoxShadow(
- color: Colors.grey[200]!.withValues(alpha: 0.8),
- blurRadius: 10,
- offset: const Offset(0, 4),
- ),
- ],
- ),
- child: Column(
- children: [
- // 搜索框
- Container(
- decoration: BoxDecoration(
- color: Colors.grey[50],
- borderRadius: BorderRadius.circular(12),
- border: Border.all(color: Colors.blue[200]!, width: 1),
- ),
- child: TextField(
- controller: _searchController,
- decoration: InputDecoration(
- hintText: '搜索日志内容...',
- hintStyle: TextStyle(color: Colors.grey[500]),
- prefixIcon: Icon(Icons.search, color: Colors.blue[600]),
- border: InputBorder.none,
- contentPadding: const EdgeInsets.symmetric(
- horizontal: 16,
- vertical: 12,
- ),
- ),
- onChanged: (_) => _updateLogs(),
- ),
- ),
- const SizedBox(height: 12),
- // 操作按钮
- Row(
- children: [
- Expanded(
- child: ElevatedButton.icon(
- icon: const Icon(Icons.refresh, size: 18),
- label: const Text('刷新'),
- style: ElevatedButton.styleFrom(
- backgroundColor: Colors.blue[500],
- foregroundColor: Colors.white,
- elevation: 2,
- padding: const EdgeInsets.symmetric(vertical: 12),
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(10),
- ),
- ),
- onPressed: _updateLogs,
- ),
- ),
- const SizedBox(width: 12),
- Expanded(
- child: ElevatedButton.icon(
- icon: const Icon(Icons.clear_all, size: 18),
- label: const Text('清除'),
- style: ElevatedButton.styleFrom(
- backgroundColor: Colors.red[500],
- foregroundColor: Colors.white,
- elevation: 2,
- padding: const EdgeInsets.symmetric(vertical: 12),
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(10),
- ),
- ),
- onPressed: () {
- IXDeveloperTools.clearLogs();
- _updateLogs();
- },
- ),
- ),
- ],
- ),
- ],
- ),
- ),
- // 日志列表
- Expanded(
- child: _filteredLogs.isEmpty
- ? Center(
- child: Container(
- padding: const EdgeInsets.all(32),
- child: Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- Container(
- padding: const EdgeInsets.all(20),
- decoration: BoxDecoration(
- gradient: LinearGradient(
- colors: [Colors.blue[100]!, Colors.purple[100]!],
- ),
- shape: BoxShape.circle,
- ),
- child: Icon(
- Icons.terminal,
- size: 48,
- color: Colors.blue[600],
- ),
- ),
- const SizedBox(height: 16),
- Text(
- '暂无日志',
- style: TextStyle(
- fontSize: 18,
- fontWeight: FontWeight.bold,
- color: Colors.grey[600],
- ),
- ),
- const SizedBox(height: 8),
- Text(
- '开始使用应用后,日志将显示在这里',
- style: TextStyle(
- fontSize: 14,
- color: Colors.grey[500],
- ),
- ),
- ],
- ),
- ),
- )
- : RefreshIndicator(
- onRefresh: () async {
- _updateLogs();
- },
- child: ListView.builder(
- physics: const AlwaysScrollableScrollPhysics(),
- itemCount: _filteredLogs.length,
- itemBuilder: (context, index) {
- final log = _filteredLogs[index];
- return SimpleLogCard(log: log);
- },
- ),
- ),
- ),
- ],
- );
- }
- }
- /// 简化版API监控标签页
- class SimpleApiMonitorTab extends StatefulWidget {
- const SimpleApiMonitorTab({super.key});
- @override
- State<SimpleApiMonitorTab> createState() => _SimpleApiMonitorTabState();
- }
- class _SimpleApiMonitorTabState extends State<SimpleApiMonitorTab> {
- @override
- Widget build(BuildContext context) {
- final requests = IXDeveloperTools.apiRequests;
- return Column(
- children: [
- // 操作栏
- Container(
- margin: const EdgeInsets.all(16),
- padding: const EdgeInsets.all(16),
- decoration: BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.circular(16),
- boxShadow: [
- BoxShadow(
- color: Colors.grey[200]!.withValues(alpha: 0.8),
- blurRadius: 10,
- offset: const Offset(0, 4),
- ),
- ],
- ),
- child: Column(
- children: [
- // 统计信息
- Container(
- width: double.infinity,
- padding: const EdgeInsets.all(12),
- decoration: BoxDecoration(
- gradient: LinearGradient(
- colors: [Colors.blue[50]!, Colors.purple[50]!],
- ),
- borderRadius: BorderRadius.circular(12),
- border: Border.all(color: Colors.blue[200]!, width: 1),
- ),
- child: Row(
- children: [
- Icon(Icons.analytics, color: Colors.blue[600], size: 20),
- const SizedBox(width: 8),
- Text(
- '共 ${requests.length} 个请求',
- style: TextStyle(
- fontSize: 16,
- fontWeight: FontWeight.bold,
- color: Colors.blue[700],
- ),
- ),
- const Spacer(),
- Container(
- padding: const EdgeInsets.symmetric(
- horizontal: 8,
- vertical: 4,
- ),
- decoration: BoxDecoration(
- color: Colors.blue[100],
- borderRadius: BorderRadius.circular(8),
- ),
- child: Text(
- '实时监控',
- style: TextStyle(
- fontSize: 12,
- color: Colors.blue[700],
- fontWeight: FontWeight.w500,
- ),
- ),
- ),
- ],
- ),
- ),
- const SizedBox(height: 12),
- // 操作按钮
- Row(
- children: [
- Expanded(
- child: ElevatedButton.icon(
- icon: const Icon(Icons.refresh, size: 18),
- label: const Text('刷新'),
- style: ElevatedButton.styleFrom(
- backgroundColor: Colors.green[500],
- foregroundColor: Colors.white,
- elevation: 2,
- padding: const EdgeInsets.symmetric(vertical: 12),
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(10),
- ),
- ),
- onPressed: () => setState(() {}),
- ),
- ),
- const SizedBox(width: 12),
- Expanded(
- child: ElevatedButton.icon(
- icon: const Icon(Icons.clear_all, size: 18),
- label: const Text('清除'),
- style: ElevatedButton.styleFrom(
- backgroundColor: Colors.orange[500],
- foregroundColor: Colors.white,
- elevation: 2,
- padding: const EdgeInsets.symmetric(vertical: 12),
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.circular(10),
- ),
- ),
- onPressed: () {
- IXDeveloperTools.clearApiRequests();
- setState(() {});
- },
- ),
- ),
- ],
- ),
- ],
- ),
- ),
- // API请求列表
- Expanded(
- child: requests.isEmpty
- ? Center(
- child: Container(
- padding: const EdgeInsets.all(32),
- child: Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- Container(
- padding: const EdgeInsets.all(20),
- decoration: BoxDecoration(
- gradient: LinearGradient(
- colors: [Colors.green[100]!, Colors.blue[100]!],
- ),
- shape: BoxShape.circle,
- ),
- child: Icon(
- Icons.network_check,
- size: 48,
- color: Colors.green[600],
- ),
- ),
- const SizedBox(height: 16),
- Text(
- '暂无API请求',
- style: TextStyle(
- fontSize: 18,
- fontWeight: FontWeight.bold,
- color: Colors.grey[600],
- ),
- ),
- const SizedBox(height: 8),
- Text(
- '开始网络请求后,API信息将显示在这里',
- style: TextStyle(
- fontSize: 14,
- color: Colors.grey[500],
- ),
- ),
- ],
- ),
- ),
- )
- : RefreshIndicator(
- onRefresh: () async {
- setState(() {});
- },
- child: ListView.builder(
- physics: const AlwaysScrollableScrollPhysics(),
- itemCount: requests.length,
- itemBuilder: (context, index) {
- final request = requests[index];
- return SimpleApiCard(request: request);
- },
- ),
- ),
- ),
- ],
- );
- }
- }
|