lumin_ui 1.0.17 copy "lumin_ui: ^1.0.17" to clipboard
lumin_ui: ^1.0.17 copied to clipboard

A modern Flutter UI component library with GetX integration, providing rich customizable components and smart text overflow handling.

Lumin UI 🌟 #

Pub Version License: MIT Flutter Dart CI codecov

A comprehensive Flutter UI library providing beautiful, customizable, and high-performance components for modern mobile and web applications.

一个基于 Flutter 的现代化 UI 组件库,集成了 GetX 状态管理,提供丰富的可定制组件。

特性 #

  • 🎨 现代化设计 - 遵循 Material Design 3 设计规范
  • 🚀 高性能 - 基于 Flutter 原生组件构建
  • 🔧 高度可定制 - 支持主题定制和样式覆盖
  • 📱 响应式 - 适配不同屏幕尺寸
  • 🎯 GetX 集成 - 内置状态管理和路由管理
  • 📦 开箱即用 - 提供常用业务组件

安装 #

pubspec.yaml 中添加依赖:

dependencies:
  lumin: ^1.0.0
  get: ^4.6.6
  intl: ^0.19.0

快速开始 #

1. 初始化应用 #

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:lumin/ui/core.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      title: 'Lumin UI Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: HomePage(),
    );
  }
}

2. 使用组件 #

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Lumin UI Demo')),
      body: Padding(
        padding: EdgeInsets.all(16),
        child: Column(
          children: [
            // 文本组件
            luminText('Hello Lumin UI!'),
            
            // 按钮组件
            LuminButtons.primary(
              text: '主要按钮',
              onPressed: () => print('按钮被点击'),
            ),
            
            // 输入框组件
            LuminTextField(
              label: '用户名',
              placeholder: '请输入用户名',
              prefixIcon: Icons.person,
            ),
          ],
        ),
      ),
    );
  }
}

组件文档 #

文本组件 (LuminText) #

用于显示文本内容,支持占位符、前缀、后缀等功能。

luminText(
  '显示文本',
  style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold),
  placeholder: '暂无数据',
  prefix: '前缀',
  suffix: '后缀',
)

按钮组件 (LuminButton) #

提供多种样式的按钮组件。

// 基础按钮
LuminButton(
  text: '按钮文本',
  onPressed: () {},
  style: LuminButtonStyle.filled, // filled, outlined, text
)

// 预设样式按钮
LuminButtons.primary(text: '主要按钮', onPressed: () {})
LuminButtons.secondary(text: '次要按钮', onPressed: () {})
LuminButtons.danger(text: '危险按钮', onPressed: () {})
LuminButtons.success(text: '成功按钮', onPressed: () {})

输入框组件 (LuminTextField) #

增强的文本输入框,支持多种输入类型和验证。

LuminTextField(
  controller: controller,
  label: '标签',
  placeholder: '占位符',
  inputType: LuminInputType.email, // text, password, email, phone, number 等
  prefixIcon: Icons.email,
  suffixIcon: Icons.visibility,
  clearable: true,
  validator: (value) => value?.isEmpty == true ? '不能为空' : null,
)

下拉框组件 (LuminDropdown) #

支持单选和多选的下拉框组件。

// 单选下拉框
LuminDropdown<String>(
  value: selectedValue,
  items: [
    LuminDropdownItem(value: 'option1', label: '选项1'),
    LuminDropdownItem(value: 'option2', label: '选项2'),
  ],
  onChanged: (value) => setState(() => selectedValue = value),
  placeholder: '请选择',
)

// 多选下拉框
LuminMultiSelectDropdown<String>(
  values: selectedValues,
  items: [
    LuminDropdownItem(value: 'option1', label: '选项1'),
    LuminDropdownItem(value: 'option2', label: '选项2'),
  ],
  onChanged: (values) => setState(() => selectedValues = values),
)

对话框组件 (LuminDialog) #

提供多种类型的对话框。

// 基础对话框
LuminDialog.show(
  title: '标题',
  content: '内容',
  actions: [
    TextButton(onPressed: () => Get.back(), child: Text('取消')),
    ElevatedButton(onPressed: () => Get.back(), child: Text('确认')),
  ],
);

// 确认对话框
final result = await LuminDialog.confirm(
  title: '确认删除',
  content: '确定要删除这个项目吗?',
);

// 输入对话框
final input = await LuminDialog.input(
  title: '输入名称',
  placeholder: '请输入名称',
);

// 选择对话框
final selected = await LuminDialog.select<String>(
  title: '选择选项',
  options: [
    LuminSelectOption(value: 'option1', label: '选项1'),
    LuminSelectOption(value: 'option2', label: '选项2'),
  ],
);

日期时间选择器 (LuminDatePicker) #

提供日期、时间、日期时间和日期范围选择功能。

// 日期选择器
final date = await LuminDatePicker.show(
  context: context,
  initialDate: DateTime.now(),
  firstDate: DateTime(2020),
  lastDate: DateTime(2030),
);

// 时间选择器
final time = await LuminTimePicker.show(
  context: context,
  initialTime: TimeOfDay.now(),
);

// 日期时间选择器
final dateTime = await LuminDateTimePicker.show(
  context: context,
  initialDateTime: DateTime.now(),
);

// 日期范围选择器
final dateRange = await LuminDateRangePicker.show(
  context: context,
  initialDateRange: DateTimeRange(
    start: DateTime.now(),
    end: DateTime.now().add(Duration(days: 7)),
  ),
);

// 时间范围选择器
LuminTimeRangePicker(
  label: '时间范围',
  selectedRange: timeRange,
  onRangeChanged: (range) => setState(() => timeRange = range),
  hintText: '请选择时间范围',
)

// 日期时间范围选择器
LuminDateTimeRangePicker(
  label: '日期时间范围',
  selectedRange: dateTimeRange,
  onRangeChanged: (range) => setState(() => dateTimeRange = range),
  hintText: '请选择日期时间范围',
)

分页组件 (LuminPagination) #

提供完整的分页功能。

// 基础分页
LuminPagination(
  currentPage: currentPage,
  totalPages: totalPages,
  onPageChanged: (page) => setState(() => currentPage = page),
)

// 完整分页(包含页面大小选择器和信息显示)
LuminFullPagination(
  currentPage: currentPage,
  totalPages: totalPages,
  totalItems: totalItems,
  pageSize: pageSize,
  onPageChanged: (page) => setState(() => currentPage = page),
  onPageSizeChanged: (size) => setState(() => pageSize = size),
)

容器组件 (LuminContainer) #

增强的容器组件,支持渐变、边框、阴影等效果。

luminContainer(
  child: Text('容器内容'),
  backgroundColor: Colors.blue.shade50,
  borderRadius: 12,
  border: Border.all(color: Colors.blue),
  gradient: LinearGradient(
    colors: [Colors.blue.shade100, Colors.blue.shade200],
  ),
  elevation: 4,
  padding: EdgeInsets.all(16),
  margin: EdgeInsets.all(8),
)

Flex 布局扩展 (LuminFlex) #

为 Widget 列表提供便捷的布局方法。

// 水平布局
[widget1, widget2, widget3].toRow(spacing: 8)

// 垂直布局
[widget1, widget2, widget3].toColumn(spacing: 8)

// 包装布局
[widget1, widget2, widget3].toWrap(spacing: 8, runSpacing: 8)

表单字段组件 (LuminFormField) #

统一的表单字段组件,支持多种输入类型和自定义样式。

// 普通文本输入
LuminFormFields.text(
  label: '姓名',
  placeholder: '请输入姓名',
  isRequired: true,
  rightWidget: Icon(Icons.person),
)

// 数字输入(带单位)
LuminFormFields.number(
  label: '重量',
  placeholder: '请输入重量',
  unit: 'KG',
  isRequired: true,
)

// 下拉选择
LuminFormFields.dropdown(
  label: '城市',
  options: ['北京', '上海', '广州', '深圳'],
  placeholder: '请选择城市',
  rightWidget: Icon(Icons.arrow_forward_ios, size: 16),
)

// 多行文本
LuminFormFields.multiline(
  label: '备注',
  placeholder: '请输入备注信息',
  maxLines: 3,
)

// 开关
LuminFormFields.switch_(
  label: '启用通知',
  initialValue: true,
)

// 步进器
LuminFormFields.stepper(
  label: '数量',
  min: 0,
  max: 100,
  step: 1,
  initialValue: 1,
)

// 自定义组件
LuminFormFields.custom(
  label: '自定义',
  customWidget: YourCustomWidget(),
  rightWidget: Icon(Icons.settings),
)

表单字段特性

  • 统一样式: 所有字段保持一致的视觉风格
  • 必填标识: 支持红色星号标记必填字段
  • 右侧扩展: 可添加自定义右侧组件(图标、按钮等)
  • 单位支持: 数字输入框支持单位显示
  • 验证集成: 内置表单验证支持
  • 响应式: 集成GetX响应式状态管理
  • 多种类型: 支持文本、数字、下拉、开关、步进器等
  • 样式自定义: 支持边框、标题、输入框、箭头等样式配置

样式配置选项

// 自定义样式示例
LuminFormFields.text(
  label: '自定义样式',
  placeholder: '请输入内容',
  // 边框配置
  borderColor: Colors.blue,
  showBorder: true,
  // 标题配置
  labelColor: Colors.blue.shade700,
  labelFontSize: 18,
  // 输入框配置
  inputBackgroundColor: Colors.blue.shade50,
)

// 下拉选择框箭头配置
LuminFormFields.dropdown(
  label: '选择项',
  options: ['选项1', '选项2'],
  // 箭头配置
  showArrow: true,
  arrowColor: Colors.grey.shade600,
  // 无边框样式
  showBorder: false,
)

表格组件 (LuminTable) #

功能强大的表格组件,支持自定义表头、表头合并、固定列、左右滑动、分页等功能。

// 基础表格
LuminTables.basic(
  columns: [
    LuminTableColumn(key: 'name', title: '姓名', width: 100),
    LuminTableColumn(key: 'age', title: '年龄', width: 80, textAlign: TextAlign.center),
    LuminTableColumn(key: 'city', title: '城市', width: 100),
  ],
  data: data.map((item) => LuminTableRow(
    data: item,
    onTap: () => print('点击了${item['name']}'),
  )).toList(),
  config: LuminTableConfig(
    showBorder: true,
    showRowDivider: true,
    hoverColor: Colors.grey.shade100,
  ),
)

// 分页表格
LuminTables.paginated(
  columns: [
    LuminTableColumn(
      key: 'id', 
      title: 'ID', 
      width: 60, 
      fixed: true, // 固定列
      textAlign: TextAlign.center,
    ),
    LuminTableColumn(
      key: 'name', 
      title: '姓名', 
      width: 120,
      sortable: true, // 可排序
    ),
    LuminTableColumn(
      key: 'status', 
      title: '状态', 
      width: 100,
      cellBuilder: (context, data, column) {
        // 自定义单元格内容
        final status = data['status'] as String;
        Color color = status == '活跃' ? Colors.green : Colors.red;
        return Container(
          padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
          decoration: BoxDecoration(
            color: color.withOpacity(0.1),
            borderRadius: BorderRadius.circular(12),
            border: Border.all(color: color.withOpacity(0.3)),
          ),
          child: Text(
            status,
            style: TextStyle(color: color, fontSize: 12),
          ),
        );
      },
    ),
    LuminTableColumn(
      key: 'actions', 
      title: '操作', 
      width: 120,
      cellBuilder: (context, data, column) {
        return Row(
          mainAxisSize: MainAxisSize.min,
          children: [
            TextButton(
              onPressed: () => print('编辑${data['name']}'),
              child: Text('编辑', style: TextStyle(fontSize: 12)),
            ),
            TextButton(
              onPressed: () => print('删除${data['name']}'),
              child: Text('删除', style: TextStyle(fontSize: 12, color: Colors.red)),
            ),
          ],
        );
      },
    ),
  ],
  data: currentData.map((item) => LuminTableRow(
    data: item,
    onTap: () => print('点击了${item['name']}'),
  )).toList(),
  config: LuminTableConfig(
    showBorder: true,
    showRowDivider: true,
    showColumnDivider: true,
    hoverColor: Colors.blue.shade50,
    headerBackgroundColor: Colors.grey.shade100,
    height: 300, // 固定高度,支持滚动
  ),
  paginationConfig: LuminTablePaginationConfig(
    currentPage: currentPage,
    totalPages: totalPages,
    pageSize: pageSize,
    pageSizeOptions: [5, 10, 20, 50],
    onPageChanged: (page) => setState(() => currentPage = page),
    onPageSizeChanged: (size) => setState(() => pageSize = size),
    showPageSizeSelector: true,
    showPageInfo: true,
  ),
  sortConfig: LuminTableSort(
    column: sortColumn,
    ascending: sortAscending,
    onSort: (column, ascending) {
      setState(() {
        sortColumn = column;
        sortAscending = ascending;
      });
    },
  ),
)

// 表头合并示例
LuminTable(
  columns: [
    LuminTableColumn(
      key: 'name', 
      title: '基本信息', 
      width: 100,
      colspan: 2, // 合并2列
      headerBuilder: (context, column) {
        return Container(
          alignment: Alignment.center,
          padding: EdgeInsets.all(12),
          decoration: BoxDecoration(
            color: Colors.blue.shade100,
            border: Border.all(color: Colors.grey.shade300),
          ),
          child: Text(
            column.title,
            style: TextStyle(fontWeight: FontWeight.bold),
          ),
        );
      },
    ),
    LuminTableColumn(key: 'age', title: '', width: 80, isSubHeader: true),
    LuminTableColumn(
      key: 'score', 
      title: '成绩信息', 
      width: 100,
      colspan: 2,
      headerBuilder: (context, column) {
        return Container(
          alignment: Alignment.center,
          padding: EdgeInsets.all(12),
          decoration: BoxDecoration(
            color: Colors.green.shade100,
            border: Border.all(color: Colors.grey.shade300),
          ),
          child: Text(
            column.title,
            style: TextStyle(fontWeight: FontWeight.bold),
          ),
        );
      },
    ),
    LuminTableColumn(key: 'status', title: '', width: 80, isSubHeader: true),
  ],
  data: data.map((item) => LuminTableRow(data: item)).toList(),
  config: LuminTableConfig(
    showBorder: true,
    showRowDivider: true,
    showColumnDivider: true,
    height: 200,
  ),
)

表格组件特性

  • 自定义表头: 支持自定义表头样式和内容
  • 表头合并: 支持跨列合并表头单元格
  • 固定列: 支持左侧固定列,右侧可滚动
  • 左右滑动: 当内容超出屏幕宽度时支持水平滚动
  • 分页功能: 集成现有分页组件,支持页面大小选择
  • 排序功能: 支持列排序,可自定义排序逻辑
  • 行选择: 支持单选和多选行
  • 自定义单元格: 支持自定义单元格内容和样式
  • 悬停效果: 支持行悬停高亮效果
  • 边框控制: 支持表格边框、行分割线、列分割线的显示控制
  • 响应式: 支持不同屏幕尺寸的适配

表格配置选项

// 列配置
LuminTableColumn(
  key: 'column_key',           // 列标识
  title: '列标题',              // 列标题
  width: 100,                  // 列宽度
  minWidth: 80,                // 最小宽度
  maxWidth: 200,               // 最大宽度
  fixed: false,                // 是否固定列
  sortable: false,             // 是否可排序
  textAlign: TextAlign.left,   // 文本对齐方式
  colspan: 1,                  // 表头合并列数
  rowspan: 1,                  // 表头合并行数
  isSubHeader: false,          // 是否为子表头
  cellBuilder: (context, data, column) => Widget, // 自定义单元格
  headerBuilder: (context, column) => Widget,      // 自定义表头
)

// 表格配置
LuminTableConfig(
  showBorder: true,                    // 显示外边框
  showRowDivider: true,                // 显示行分割线
  showColumnDivider: false,            // 显示列分割线
  hoverColor: Colors.grey.shade100,    // 悬停颜色
  selectedColor: Colors.blue.shade100, // 选中颜色
  headerBackgroundColor: Colors.grey.shade50, // 表头背景色
  borderColor: Colors.grey.shade300,   // 边框颜色
  dividerColor: Colors.grey.shade200,  // 分割线颜色
  height: 400,                         // 表格高度
  headerHeight: 48,                    // 表头高度
  rowHeight: 48,                       // 行高度
)

// 分页配置
LuminTablePaginationConfig(
  currentPage: 1,                      // 当前页码
  totalPages: 10,                      // 总页数
  pageSize: 10,                        // 每页大小
  pageSizeOptions: [10, 20, 50],       // 页面大小选项
  showPageSizeSelector: true,          // 显示页面大小选择器
  showPageInfo: true,                  // 显示页面信息
  onPageChanged: (page) {},            // 页码变化回调
  onPageSizeChanged: (size) {},        // 页面大小变化回调
)

GetX 集成 #

控制器基类 #

Lumin UI 提供了几个控制器基类来简化状态管理:

// 基础控制器
class MyController extends LuminController {
  void doSomething() async {
    await executeAsync(
      operation: () => apiCall(),
      loadingMessage: '加载中...',
      successMessage: '操作成功',
      showLoadingDialog: true,
      showSuccessSnackbar: true,
    );
  }
}

// 列表控制器
class MyListController extends LuminListController<MyModel> {
  @override
  Future<void> loadData({bool showLoading = true}) async {
    final data = await apiService.getList(
      page: currentPage,
      pageSize: pageSize,
      keyword: searchKeyword,
    );
    
    if (currentPage == 1) {
      items = data.items;
    } else {
      items.addAll(data.items);
    }
    
    totalPages = data.totalPages;
    totalItems = data.totalItems;
    hasMore = currentPage < totalPages;
  }
}

// 表单控制器
class MyFormController extends LuminFormController {
  @override
  Future<void> submitForm() async {
    if (!validateForm()) return;
    
    await executeAsync(
      operation: () => apiService.submit({
        'name': getFieldValue('name'),
        'email': getFieldValue('email'),
      }),
      loadingMessage: '提交中...',
      successMessage: '提交成功',
      showLoadingDialog: true,
      showSuccessSnackbar: true,
    );
  }
}

GetX 工具类 #

// 显示确认对话框
final confirmed = await LuminGetX.showConfirmDialog(
  title: '确认操作',
  message: '确定要执行此操作吗?',
);

// 显示输入对话框
final input = await LuminGetX.showInputDialog(
  title: '输入信息',
  hintText: '请输入内容',
);

// 显示选择对话框
final selected = await LuminGetX.showSelectDialog<String>(
  title: '选择选项',
  options: [
    LuminSelectOption(value: 'option1', label: '选项1'),
    LuminSelectOption(value: 'option2', label: '选项2'),
  ],
);

// 显示底部选择器
final selected = await LuminGetX.showBottomPicker<String>(
  title: '选择选项',
  options: [
    LuminSelectOption(value: 'option1', label: '选项1'),
    LuminSelectOption(value: 'option2', label: '选项2'),
  ],
);

// 显示自定义 Snackbar
LuminGetX.showSnackbar(
  title: '提示',
  message: '这是一个提示消息',
  backgroundColor: Colors.blue,
  icon: Icon(Icons.info),
);

主题定制 #

你可以通过 Flutter 的主题系统来定制 Lumin UI 组件的外观:

GetMaterialApp(
  theme: ThemeData(
    colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
    useMaterial3: true,
    // 自定义按钮主题
    elevatedButtonTheme: ElevatedButtonThemeData(
      style: ElevatedButton.styleFrom(
        borderRadius: BorderRadius.circular(8),
      ),
    ),
    // 自定义输入框主题
    inputDecorationTheme: InputDecorationTheme(
      border: OutlineInputBorder(
        borderRadius: BorderRadius.circular(8),
      ),
    ),
  ),
  home: HomePage(),
)

示例项目 #

查看 lib/main.dart 文件获取完整的使用示例。

网络请求 #

网络管理器 (LuminNetworkManager) #

Lumin UI 提供了强大的网络请求管理功能,基于 Dio 封装,支持请求拦截、响应处理、错误处理等。

// 初始化网络管理器
final networkManager = LuminNetworkManager(
  config: LuminNetworkConfig(
    baseUrl: 'https://api.example.com',
    connectTimeout: const Duration(seconds: 30),
    receiveTimeout: const Duration(seconds: 30),
    headers: {
      'Content-Type': 'application/json',
      'Accept': 'application/json',
    },
  ),
);

// 添加请求拦截器
networkManager.addRequestInterceptor(
  onRequest: (options, handler) {
    // 添加认证token
    final token = AuthService.getToken();
    if (token != null) {
      options.headers['Authorization'] = 'Bearer $token';
    }
    handler.next(options);
  },
);

// 添加响应拦截器
networkManager.addResponseInterceptor(
  onResponse: (response, handler) {
    // 处理响应数据
    print('响应状态: ${response.statusCode}');
    handler.next(response);
  },
  onError: (error, handler) {
    // 处理错误
    if (error.response?.statusCode == 401) {
      // token过期,跳转到登录页
      Get.offAllNamed('/login');
    }
    handler.next(error);
  },
);

基础请求方法

// GET 请求
LuminResponse<Map<String, dynamic>> response = await networkManager.get(
  '/api/users',
  queryParameters: {'page': 1, 'limit': 10},
);

if (response.isSuccess) {
  print('用户列表: ${response.data}');
} else {
  print('请求失败: ${response.message}');
}

// POST 请求
LuminResponse<Map<String, dynamic>> response = await networkManager.post(
  '/api/users',
  data: {
    'name': 'John Doe',
    'email': 'john@example.com',
  },
);

// PUT 请求
LuminResponse<Map<String, dynamic>> response = await networkManager.put(
  '/api/users/123',
  data: {'name': 'Jane Doe'},
);

// DELETE 请求
LuminResponse<bool> response = await networkManager.delete('/api/users/123');

文件上传下载

// 图片选择和上传
class ImageUploadController extends GetxController with LuminNetworkMixin {
  final ImagePicker _imagePicker = ImagePicker();
  final uploadProgress = 0.0.obs;
  final uploadedImageUrl = ''.obs;
  final selectedImage = Rxn<File>();

  @override
  void onInit() {
    super.onInit();
    // 初始化网络管理器
    initNetworkManager(LuminNetworkConfig(
      baseUrl: 'https://api.example.com',
      connectTimeout: const Duration(seconds: 30),
      receiveTimeout: const Duration(seconds: 30),
    ));
  }

  // 选择图片
  Future<void> pickImage() async {
    try {
      final XFile? image = await _imagePicker.pickImage(
        source: ImageSource.gallery,
        maxWidth: 1920,
        maxHeight: 1080,
        imageQuality: 85,
      );
      
      if (image != null) {
        selectedImage.value = File(image.path);
        uploadProgress.value = 0.0;
        uploadedImageUrl.value = '';
      }
    } catch (e) {
      Get.snackbar('错误', '选择图片失败: $e');
    }
  }

  // 上传图片
  Future<void> uploadImage() async {
    if (selectedImage.value == null) {
      Get.snackbar('提示', '请先选择图片');
      return;
    }

    try {
      // 创建FormData
      FormData formData = FormData.fromMap({
        'file': await MultipartFile.fromFile(
          selectedImage.value!.path,
          filename: 'image_${DateTime.now().millisecondsSinceEpoch}.jpg',
        ),
        'type': 'image',
        'description': '用户上传的图片',
      });

      // 执行上传请求
      await executeRequest<Map<String, dynamic>>(
        () => networkManager.upload(
          '/api/upload/image',
          formData,
          onSendProgress: (sent, total) {
            uploadProgress.value = sent / total;
          },
        ),
        onSuccess: (response) {
          if (response.data != null && response.data!['url'] != null) {
            uploadedImageUrl.value = response.data!['url'];
            Get.snackbar('成功', '图片上传成功');
          }
        },
        onError: (error) {
          uploadProgress.value = 0.0;
          Get.snackbar('错误', '上传失败: ${error.message}');
        },
        showLoading: true,
        loadingText: '正在上传图片...',
      );
    } catch (e) {
      uploadProgress.value = 0.0;
      Get.snackbar('错误', '上传异常: $e');
    }
  }

  // 多张图片上传
  Future<void> uploadMultipleImages() async {
    try {
      final List<XFile> images = await _imagePicker.pickMultiImage(
        maxWidth: 1920,
        maxHeight: 1080,
        imageQuality: 85,
      );

      if (images.isEmpty) return;

      List<Future<LuminResponse<Map<String, dynamic>>>> uploadTasks = [];
      
      for (int i = 0; i < images.length; i++) {
        FormData formData = FormData.fromMap({
          'file': await MultipartFile.fromFile(
            images[i].path,
            filename: 'image_${i}_${DateTime.now().millisecondsSinceEpoch}.jpg',
          ),
          'type': 'image',
          'batch_id': DateTime.now().millisecondsSinceEpoch.toString(),
        });

        uploadTasks.add(networkManager.upload('/api/upload/batch', formData));
      }

      // 并发上传多张图片
      await executeMultipleRequests(
        uploadTasks,
        onSuccess: (responses) {
          int successCount = responses.where((r) => r.isSuccess).length;
          Get.snackbar('完成', '成功上传 $successCount/${images.length} 张图片');
        },
        onError: (error) {
          Get.snackbar('错误', '批量上传失败: ${error.message}');
        },
        showLoading: true,
        loadingText: '正在批量上传图片...',
      );
    } catch (e) {
      Get.snackbar('错误', '批量上传异常: $e');
    }
  }
}

// 文件下载
LuminResponse<ResponseBody> response = await networkManager.download(
  '/api/download/file.pdf',
  savePath: '/path/to/save/file.pdf',
  onReceiveProgress: (received, total) {
    print('下载进度: ${(received / total * 100).toStringAsFixed(1)}%');
  },
);

网络混入 (LuminNetworkMixin)

为了简化网络请求的使用,Lumin UI 提供了网络混入类:

class ApiController extends GetxController with LuminNetworkMixin {
  @override
  void onInit() {
    super.onInit();
    // 初始化网络管理器
    initNetworkManager(LuminNetworkConfig(
      baseUrl: 'https://api.example.com',
    ));
  }

  // 获取用户列表
  Future<void> getUserList() async {
    await executeRequest<List<Map<String, dynamic>>>(
      () => networkManager.get('/api/users'),
      onSuccess: (response) {
        // 处理成功响应
        print('用户列表: ${response.data}');
      },
      onError: (error) {
        // 处理错误
        Get.snackbar('错误', error.message);
      },
      showLoading: true,
      loadingText: '正在加载用户列表...',
    );
  }

  // 创建用户
  Future<void> createUser(Map<String, dynamic> userData) async {
    await executeRequest<Map<String, dynamic>>(
      () => networkManager.post('/api/users', data: userData),
      onSuccess: (response) {
        Get.snackbar('成功', '用户创建成功');
        getUserList(); // 刷新列表
      },
      onError: (error) {
        Get.snackbar('错误', '创建失败: ${error.message}');
      },
      showLoading: true,
      loadingText: '正在创建用户...',
    );
  }

  // 批量请求
  Future<void> loadDashboardData() async {
    await executeMultipleRequests([
      networkManager.get('/api/users/count'),
      networkManager.get('/api/orders/count'),
      networkManager.get('/api/revenue/today'),
    ],
    onSuccess: (responses) {
      // 处理所有响应
      final userCount = responses[0].data;
      final orderCount = responses[1].data;
      final todayRevenue = responses[2].data;
      print('仪表板数据加载完成');
    },
    onError: (error) {
      Get.snackbar('错误', '数据加载失败: ${error.message}');
    },
    showLoading: true,
    loadingText: '正在加载仪表板数据...',
    );
  }
}

响应模型

// 统一响应模型
class LuminResponse<T> {
  final bool isSuccess;
  final int statusCode;
  final String message;
  final T? data;
  final Map<String, dynamic>? headers;
  final dynamic originalResponse;

  LuminResponse({
    required this.isSuccess,
    required this.statusCode,
    required this.message,
    this.data,
    this.headers,
    this.originalResponse,
  });

  // 成功响应
  factory LuminResponse.success({
    required T data,
    int statusCode = 200,
    String message = 'Success',
    Map<String, dynamic>? headers,
    dynamic originalResponse,
  }) {
    return LuminResponse<T>(
      isSuccess: true,
      statusCode: statusCode,
      message: message,
      data: data,
      headers: headers,
      originalResponse: originalResponse,
    );
  }

  // 错误响应
  factory LuminResponse.error({
    required String message,
    int statusCode = 500,
    Map<String, dynamic>? headers,
    dynamic originalResponse,
  }) {
    return LuminResponse<T>(
      isSuccess: false,
      statusCode: statusCode,
      message: message,
      headers: headers,
      originalResponse: originalResponse,
    );
  }
}

贡献 #

欢迎提交 Issue 和 Pull Request 来帮助改进这个项目。

许可证 #

MIT License

1
likes
40
points
23
downloads

Documentation

Documentation

Publisher

unverified uploader

Weekly Downloads

A modern Flutter UI component library with GetX integration, providing rich customizable components and smart text overflow handling.

Homepage
Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

connectivity_plus, cupertino_icons, device_info_plus, dio, flutter, flutter_localizations, get, image_picker, intl, pull_to_refresh, shared_preferences, webview_flutter, webview_flutter_android

More

Packages that depend on lumin_ui