flutter_chen_common 5.11.0 copy "flutter_chen_common: ^5.11.0" to clipboard
flutter_chen_common: ^5.11.0 copied to clipboard

The flutter common package designed to help developers swiftly build aesthetically pleasing and feature-rich mobile application interfaces.

example/lib/main.dart

import 'dart:io';

import 'package:dio/dio.dart';
import 'package:example/network/network_interceptor.dart';
import 'package:example/pages/component/component.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_chen_common/flutter_chen_common.dart';
import 'package:flutter_chen_refresh/flutter_chen_refresh.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:get/get.dart';
import 'package:module_base/module_base.dart';
import 'package:path_provider/path_provider.dart';

final navigatorKey = GlobalKey<NavigatorState>();
final _demoSecureStorage = <String, String>{
  'access_token': 'demo-access-token',
};

const _sensitiveDebugKeys = {
  'authorization',
  'token',
  'password',
  'secret',
  'cookie',
};

bool _isSensitiveDebugKey(String? key) {
  final normalizedKey = key?.toLowerCase() ?? '';
  return _sensitiveDebugKeys.any(normalizedKey.contains);
}

dynamic _sanitizeDebugValue(dynamic value) {
  if (value is Map) {
    return value.map((key, item) {
      return MapEntry(
        key.toString(),
        _isSensitiveDebugKey(key.toString())
            ? '***'
            : _sanitizeDebugValue(item),
      );
    });
  }
  if (value is List) {
    return value.map(_sanitizeDebugValue).toList(growable: false);
  }
  return value;
}

Map<String, dynamic> _sanitizeDebugMap(Map<String, dynamic> value) =>
    Map<String, dynamic>.from(_sanitizeDebugValue(value) as Map);

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await SpUtil.init();
  AppThemeMode.initialize();
  Directory dir = await getApplicationCacheDirectory();
  await Log.init(
    LogConfig(
      retentionDays: 3,
      enableFileLog: true,
      logLevel: LogLevel.all,
      recordLevel: LogLevel.info,
      output: const [],
      // printer: PrettyPrinter(dateTimeFormat: DateTimeFormat.dateAndTime),
      logDirectory: kIsWeb ? null : Directory('${dir.path}/logs'),
    ),
  );
  HttpClient.init(
    config: HttpConfig(
      baseUrl: Env.config.baseUrl,
      connectTimeout: const Duration(seconds: 30),
      receiveTimeout: const Duration(seconds: 30),
      sendTimeout: const Duration(seconds: 30),
      commonHeaders: () => {"Authorization": SpUtil.getString('token')},
      interceptors: [NetworkInterceptor()],
      enableLog: true,
      enableToken: true,
      enableRetry: true,
      maxRetries: 3,
      retriesDelay: const Duration(seconds: 1),
      getToken: () => SpUtil.getString("token"),
      onRefreshToken: () async {
        return "new_token";
      },
      onRefreshTokenFailed: () async {
        Log.d("重新登录");
      },
    ),
  );

  await ComDebugManager.instance.init(
      dio: HttpClient.instance.dio,
      comDebugConfig: ComDebugConfig(
        enabled: Env.env != EnvEnum.prod,
        maxLogCount: 100, // 最大日志缓存数量
        enablePushDebug: true,
        enableStorageDebug: true,
        sanitize: (log) {
          // 敏感数据脱敏示例
          if (log.request?.headers.containsKey('Authorization') ?? false) {
            log.request?.headers['Authorization'] = '***';
          }
          return log;
        },
        sanitizePushLog: (log) => ComPushDebug(
          id: log.id,
          timestamp: log.timestamp,
          type: log.type,
          provider: log.provider,
          messageId: log.messageId,
          title: log.title,
          body: log.body,
          payload: _sanitizeDebugValue(log.payload),
          metadata: _sanitizeDebugMap(log.metadata),
          errorMessage: log.errorMessage,
        ),
        sanitizeStorageLog: (log) => ComStorageDebug(
          id: log.id,
          timestamp: log.timestamp,
          operation: log.operation,
          storage: log.storage,
          key: log.key,
          value: _isSensitiveDebugKey(log.key)
              ? '***'
              : _sanitizeDebugValue(log.value),
          durationMs: log.durationMs,
          success: log.success,
          errorMessage: log.errorMessage,
          metadata: _sanitizeDebugMap(log.metadata),
        ),
        loadStorageEntries: () => [
          for (final entry in SpUtil.snapshot().entries)
            ComStorageEntry(
              storage: 'preferences',
              key: entry.key,
              value: entry.value,
            ),
          for (final entry in _demoSecureStorage.entries)
            ComStorageEntry(
              storage: 'secure_storage',
              key: entry.key,
              value: entry.value,
            ),
        ],
        onDeleteStorage: (storage, key) async {
          if (storage == 'preferences') {
            return SpUtil.remove(key);
          }
          if (storage == 'secure_storage') {
            return _demoSecureStorage.remove(key) != null;
          }
          return false;
        },
        onClearStorage: () async {
          final preferencesCleared = await SpUtil.clear();
          _demoSecureStorage.clear();
          return preferencesCleared;
        },
      ));
  await _seedExtendedDebugDemoData();

  // 全局context服务初始化
  ComContext.init(navigatorKey);
  ComToast.init(
    theme: ComToastTheme(
      toast: const ComToastStateTheme(
        base: ComToastConfig(
          duration: Duration(seconds: 2),
          position: ComToastPosition.center,
        ),
        success: ComToastConfig(
          iconWidget:
              Icon(Icons.check_circle, color: Color(0xFF10B981), size: 20),
        ),
        error: ComToastConfig(
          iconWidget: Icon(Icons.cancel, color: Color(0xFFEF4444), size: 20),
        ),
        warning: ComToastConfig(
          iconWidget:
              Icon(Icons.priority_high, color: Color(0xFFF59E0B), size: 20),
        ),
        info: ComToastConfig(
          iconWidget:
              Icon(Icons.info_outline, color: Color(0xFF3B82F6), size: 20),
        ),
      ),
      loading: ComToastConfig(
        builder: (ctx) => const ComLoading(),
        clickThrough: false,
        duration: Duration.zero,
      ),
    ),
  );

  Log.d("debug message");
  Log.i("info message");
  Log.w("warning message");
  Log.e("error message");
  Log.console("console message 可完整打印不被截断并且无前缀");
  HttpClient.instance.request("https://gutendex.com/books",
      data: {"xx": "xx"}, options: Options(extra: {'custom': true}));
  HttpClient.instance.request("https://gutendex.com/books",
      data: {"xx": "xx"}, options: Options(extra: {'custom': true}));
  HttpClient.instance.request("https://gutendex.com/books",
      data: {"xx": "xx"}, options: Options(extra: {'custom': true}));
  runApp(const MyApp());
}

Future<void> _seedExtendedDebugDemoData() async {
  final manager = ComDebugManager.instance;
  manager.addPushEvent(
    type: ComPushEventType.received,
    provider: 'FCM',
    messageId: 'demo-welcome',
    title: '欢迎体验调试面板',
    body: '这是一条可检索、可复制的推送示例。',
    payload: const {
      'route': '/components',
      'campaign': 'demo',
      'token': 'demo-device-token',
    },
  );
  manager.addPushEvent(
    type: ComPushEventType.opened,
    provider: 'FCM',
    messageId: 'demo-release',
    title: '查看 5.8.0 更新',
    payload: const {'route': '/changelog'},
  );
  await SpUtil.putString('debug_demo_theme', 'system');
  manager.addStorageOperation(
    operation: ComStorageOperation.write,
    storage: 'secure_storage',
    key: 'access_token',
    value: _demoSecureStorage['access_token'],
    durationMs: 4,
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return ComConfiguration(
      config: ComConfig.defaults(),
      child: RefreshConfiguration(
        hideFooterWhenNotFull: false,
        headerBuilder: () => const ClassicHeader(),
        footerBuilder: () => const ClassicFooter(),
        child: GetMaterialApp(
          navigatorKey: navigatorKey,
          builder: (context, child) {
            ComNetworkLogger.show(context);
            return child ?? const SizedBox.shrink();
          },
          navigatorObservers: [ComToastNavigatorObserver()],
          home: const ComponentListPage(),
          title: 'Chen Common',
          theme: AppTheme.lightTheme,
          darkTheme: AppTheme.darkTheme,
          themeMode: AppThemeMode.getLocalThemeModel(),
          locale: const Locale('zh', 'CN'),
          localizationsDelegates: const [
            GlobalMaterialLocalizations.delegate,
            GlobalCupertinoLocalizations.delegate,
            GlobalWidgetsLocalizations.delegate,
          ],
          supportedLocales: const [
            Locale('zh', 'CN'),
            Locale('en', 'US'),
          ],
        ),
      ),
    );
  }
}
25
likes
160
points
942
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

The flutter common package designed to help developers swiftly build aesthetically pleasing and feature-rich mobile application interfaces.

Repository (GitHub)
View/report issues

Topics

#common

License

MIT (license)

Dependencies

dio, flutter, flutter_chen_refresh, logger, shared_preferences

More

Packages that depend on flutter_chen_common