搜尋套件、儲存庫與 APP 分類

套件詳情v2.0.0

extensionresoft

透過可重複使用的組件、實用工具和擴充功能,提升您的 Flutter 開發效率,實現高階影像處理、安全 PIN 輸入、網路連線狀態檢查等功能。

AndroidiOSmacOSWindowsLinux
近 30 天下載
467
喜歡數
8
Pub 分數
160

安裝套件

flutter pub add extensionresoft

套件介紹

根據套件公開資料產生的選型評估,僅供參考。

ExtensionResoft 是一個 Dart 套件,透過一組可重複使用的元件、工具和擴充功能來增強 Flutter 開發。它提供進階的影像處理能力、安全的 PIN 輸入元件以及可靠的網路連線檢查。設計用於簡化常見任務,減少冗餘程式碼,並提升跨多個平台的開發效率。對於尋求使用結構良好、經過測試且模組化工具加速應用建構的開發者而言,這是一個理想的選擇。

適用情境

  • 建構安全的驗證畫面
  • 處理複雜的影像操作
  • 即時檢查網路狀態
  • 建立可重複使用的 UI 元件
  • 簡化表單輸入驗證
  • 透過工具擴展提升應用效能

主要特色

  • 帶遮蔽的受保護 PIN 輸入
  • 進階影像處理工具
  • 即時網路連線偵測
  • 跨平台相容性
  • 模組化且可擴充的設計
  • 簡潔、文件完整的 API

適合對象

  • 尋求生產力提升的Flutter開發者
  • 需要安全輸入欄位的應用程式
  • 專案中涉及大量圖像處理
  • 跨平台移動和桌面應用
  • 使用一致的UI模式的團隊
  • 希望程式碼量最少的開發者

使用建議

  • 需要 Flutter SDK 3.0 或更高版本
  • 由於包含的工具,可能會稍微增加應用大小
  • 最佳搭配有組織的專案結構使用
  • 某些內建組件的自訂功能有限
  • 某些功能依賴外部相依性
  • 不適用於底層系統作業

原始 README

以下為關聯原始碼儲存庫的 README 原文快照,最新內容請造訪原始碼儲存庫。

ExtensionResoft

pub package pub points Pub Monthly Downloads likes Star on Github Awesome Flutter License: BSD

A comprehensive toolkit of extensions, widgets, and utilities to accelerate Flutter development with less code. ExtensionResoft optimizes common tasks, enhances UI components, and provides robust architecture patterns.

Features

📝 Enhanced Text/Form Field Input

Build sophisticated form fields with extensive customization:

  • CustomTextField: A highly customizable text input field with validation, dropdown support, and accessibility features.
  • Fixed Height Support: Unique height parameter that automatically calculates internal padding to ensure consistency with other widgets (like buttons) without manual calculation.
  • Validation System: Built-in validation with error, warning, and info severity levels.
  • Password Visibility: Configurable password visibility toggle with custom icons
  • Dropdown Support: Seamless integration with dropdown menus
  • Accessibility: Comprehensive semantics and validation announcements
  • Performance Optimized: Efficient state management and decoration caching
  • Theming Support: Automatic light/dark mode adaptation
  • Feedback Widget: Customizable validation messages with icons and animations
🎚️ Interactive UI Components

Create modern, responsive user interfaces:

  • CustomRangeSlider: Highly customizable dual-handle range slider with:

    • Custom theming for track, thumb, and overlay colors
    • Optional haptic feedback and accessibility labels
    • Discrete or continuous value selection with validation
    • Animated thumb scaling with Material 3 inspired design
    • Elevation shadow effects and rounded track shapes
    • Value clamping and interactive feedback
  • CustomRatingBar: Advanced star rating system with:

    • Support for half-ratings and custom icons
    • Interactive drag and tap gestures
    • Smooth animations for rating changes
    • Highly customizable appearance (colors, size, spacing)
    • Optional rating text display and custom item builders
🧬 Functional Programming Support

Write more expressive and type-safe code:

  • Either<L, R>: Comprehensive error handling with Left/Right pattern for failure/success scenarios

    • Transformation methods (map, bimap, flatMap, fold)
    • Error handling utilities (tryCatch, tryCatchAsync)
    • Combining operations (zip, zipWith) and recovery mechanisms
    • Future integration with async operation extensions
    • EitherUtils for sequence, traverse, and firstRight operations
  • Option: Elegant optional value handling with Some/None pattern

    • Core operations (fold, map, flatMap, getOrElse)
    • Conversion utilities to Either types
    • Null-safe programming patterns
  • Unit: Type-safe representation of absence of value in generic contexts

🌐 Internet Connectivity Management

Detect and respond to network changes reliably:

  • Real-time Monitoring: Observe detailed connectivity state changes through streams
  • Granular Control: Monitor specific connectivity aspects with dedicated streams
  • Simplified API: Check network status with straightforward methods
  • Resilient Applications: Build offline-ready features with minimal effort
🖼️ Advanced Image Handling

Create robust image components with minimal effort:

  • Multi-source Support: Handle network URLs, asset paths, and file objects through a unified API
  • AppImage: Rectangular images with custom border radius, intelligent error handling, and fallbacks
  • AppCircleImage: Circular avatar images with placeholder and error states
  • ImageBackground: Display images with optional overlay content for enhanced flexibility
  • Performance Optimized: Device pixel ratio-aware caching for memory efficiency
  • Decoration Support: Use as BoxDecoration background images easily
🎭 Animation Utilities

Create smooth, performant animations with minimal code:

  • AnimatedFadeScale: Combined fade and scale animation with configurable timing and curves

    • Customizable start/end scales
    • Optional delay before animation
    • Manual animation control via value parameter
    • Material transparency support
  • FadeSlideTransition: High-performance view transitions with fade and slide effects

    • Smooth content transitions with queuing support
    • Configurable slide direction and distance
    • Key-based transition triggering
    • Optimized for rapid content changes
    • Predefined fast/slow duration presets
🔐 Secure PIN Authentication UI

Build secure user authentication flows:

  • PinEntry Widget: Customizable PIN entry with multiple security configurations
  • Visual Customization: Style input fields and keyboard components separately
  • Validation Support: Custom handlers for completion and validation events
🧰 UI Extension Toolkit

Write less code for common UI patterns:

  • Spacing Extensions: Clean spacer syntax with both method and getter options
  • Custom Cards: Create styled cards with simple radius-based extensions
  • Text Styling: Format text with fluent extensions for improved readability
  • Image Path Extensions: Convert asset paths to image widgets directly
  • List Extensions: Calculate item margins with position-based utilities returning named records
🧠 Logic & Functional Extensions

Enhance code clarity and maintenance:

  • Conditional Functions: Widget-friendly alternatives to ternary operators
  • Path Extensions: Apply transformations to values with clean syntax
  • Value Management: Robust value retrieval with fallback handling

Getting Started

Installation

Add the package to your pubspec.yaml:

dependencies:
  extensionresoft: ^1.5.1

Then run:

flutter pub get
Basic Usage

Import the package:

import 'package:extensionresoft/extensionresoft.dart';

Usage Examples

Enhanced Text Input
    // Password field with visibility toggle
    CustomTextField(
      margin: EdgeInsets.symmetric(vertical: 8.0),
      labelText: 'Password',
      isPassword: true,
      passwordVisibilityConfig: PasswordVisibilityConfig(
        iconSize: 22,
        visibilityOnTooltip: 'Hide password',
        visibilityOffTooltip: 'Show password',
      ),
    );

    // Dropdown field
    CustomTextField<int>(
      labelText: 'Age Group',
      items: [
        DropdownMenuItem(value: 1, child: Text('Under 18')),
        DropdownMenuItem(value: 2, child: Text('18-25')),
        DropdownMenuItem(value: 3, child: Text('26-35')),
      ],
      onDropdownChanged: (value) {
        print('Selected age group: $value');
      },
    );

    // Styled text field with custom feedback
    CustomTextField(
      labelText: 'Email',
      hintText: 'your@email.com',
      keyboardType: TextInputType.emailAddress,
      borderRadius: BorderRadius.circular(12),
      fillColor: Colors.grey[100],
      borderColor: Colors.blueGrey,
      focusColor: Colors.blue,
      errorStyle: TextStyle(color: Colors.red[800]),
      warningStyle: TextStyle(color: Colors.orange[800]),
      helperStyle: TextStyle(color: Colors.grey),
      helperText: 'Enter a valid email address',
      feedbackShowIcons: true,
      feedbackPadding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
    );

    // Field with validation controller integration
    final validationController = ValidationController();

    // Standard height (48) matches many standard buttons
    CustomTextField(
      labelText: 'Username',
      height: 50, // Ensures consistent height and handles internal padding
      prefixIcon: Icon(Icons.person),
    );

    // Can also be used for multiple fields wrapped in a `Form`.
    CustomTextField(
      labelText: 'Order Number',
      validationController: validationController,
      validator: (value) {
        if (value == null || value.isEmpty) return 'Required field';
        if (!RegExp(r'^ORD-\d{4}$').hasMatch(value)) {
          return 'Format: ORD-1234';
        }
        return null;
      },
    );

    // Later in your code
    if (validationController.validate()) {
      // All fields valid
    }
Range Slider

Build elegant dual-handle range selectors with Material 3 design:

    // Basic range slider with custom styling
    CustomRangeSlider(
      values: RangeValues(20, 80),
      min: 0,
      max: 100,
      onChanged: (values) {
        setState(() {
          _currentRange = values;
        });
      },
      trackHeight: 4.0,
      thumbRadius: 16.0,
      enableHaptics: true,
    );

    // Custom themed range slider
    CustomRangeSlider(
      values: RangeValues(30, 70),
      min: 0,
      max: 100,
      customTheme: CustomRangeSliderTheme(
        activeTrackColor: Colors.deepPurple,
        inactiveTrackColor: Colors.grey[300],
        thumbColor: Colors.white,
        overlayColor: Colors.deepPurple.withValues(alpha: 0.12),
        thumbBorderColor: Colors.deepPurple,
      ),
      onChanged: (values) {
        print('Range: ${values.start.round()} - ${values.end.round()}');
      },
    );

    // Discrete range slider with divisions
    CustomRangeSlider(
      values: RangeValues(25, 75),
      min: 0,
      max: 100,
      divisions: 20, // Creates 20 discrete steps
      trackHeight: 6.0,
      thumbRadius: 20.0,
      onChanged: (values) {
        _updatePriceFilter(values.start, values.end);
      },
      onChangeEnd: (values) {
        // Called when user finishes dragging
        _savePricePreferences(values);
      },
    );

    // Price range selector with custom formatting
    CustomRangeSlider(
      values: RangeValues(_minPrice, _maxPrice),
      min: 0,
      max: 1000,
      divisions: 100,
      customTheme: CustomRangeSliderTheme(
        activeTrackColor: Colors.green[600],
        thumbColor: Colors.white,
        thumbBorderColor: Colors.green[600],
        overlayColor: Colors.green.withValues(alpha: 0.1),
      ),
      onChanged: (values) {
        setState(() {
          _minPrice = values.start;
          _maxPrice = values.end;
        });
      },
      semanticFormatter: (value) => '\$${value.round()}',
      enableHaptics: true,
    );

    // Safe constructor with automatic value clamping
    CustomRangeSlider.safe(
      values: RangeValues(-10, 150), // Values outside bounds
      min: 0,
      max: 100,
      // Automatically clamps to RangeValues(0, 100)
      customTheme: CustomRangeSliderTheme(
        activeTrackColor: Colors.blue[700],
        inactiveTrackColor: Colors.blue[100],
        thumbColor: Colors.white,
        thumbBorderColor: Colors.blue[700],
      ),
      onChanged: (values) {
        // Handle validated range changes
      },
    );

    // Age range selector with custom feedback
    RangeValues _ageRange = RangeValues(18, 65);
    
    Column(
      children: [
        Text(
          'Age Range: ${_ageRange.start.round()} - ${_ageRange.end.round()} years',
          style: Theme.of(context).textTheme.titleMedium,
        ),
        16.spY, // Using ExtensionResoft spacing
        CustomRangeSlider(
          values: _ageRange,
          min: 16,
          max: 100,
          divisions: 84, // One division per year
          trackHeight: 5.0,
          thumbRadius: 18.0,
          customTheme: CustomRangeSliderTheme(
            activeTrackColor: Colors.orange[600],
            inactiveTrackColor: Colors.grey[300],
            thumbColor: Colors.white,
            overlayColor: Colors.orange.withValues(alpha: 0.15),
            thumbBorderColor: Colors.orange[600],
          ),
          onChanged: (values) {
            setState(() => _ageRange = values);
          },
          semanticFormatter: (value) => '${value.round()} years old',
        ),
      ],
    );

    // Performance monitoring range (0-100%)
    CustomRangeSlider(
      values: RangeValues(_lowThreshold, _highThreshold),
      min: 0.0,
      max: 100.0,
      divisions: 100,
      trackHeight: 3.0,
      thumbRadius: 14.0,
      customTheme: CustomRangeSliderTheme(
        activeTrackColor: _getPerformanceColor(),
        thumbColor: Colors.white,
        thumbBorderColor: _getPerformanceColor(),
        overlayColor: _getPerformanceColor().withValues(alpha: 0.1),
      ),
      onChanged: (values) {
        setState(() {
          _lowThreshold = values.start;
          _highThreshold = values.end;
        });
        _updatePerformanceThresholds(values);
      },
      semanticFormatter: (value) => '${value.round()}% performance',
      enableHaptics: false, // Disable for frequent updates
    );

    // Time range selector (hours)
    CustomRangeSlider(
      values: RangeValues(_startHour.toDouble(), _endHour.toDouble()),
      min: 0,
      max: 23,
      divisions: 23,
      trackHeight: 4.0,
      thumbRadius: 16.0,
      customTheme: CustomRangeSliderTheme(
        activeTrackColor: Colors.indigo[600],
        inactiveTrackColor: Colors.indigo[100],
        thumbColor: Colors.white,
        thumbBorderColor: Colors.indigo[600],
      ),
      onChanged: (values) {
        setState(() {
          _startHour = values.start.round();
          _endHour = values.end.round();
        });
      },
      semanticFormatter: (value) {
        final hour = value.round();
        return '${hour.toString().padLeft(2, '0')}:00';
      },
    );
Rating Bar

Create interactive and animated rating systems:

    // Standard star rating
    CustomRatingBar(
      initialRating: 3.5,
      onRatingChanged: (rating) => print('Rating: $rating'),
    );

    // Highly customized rating bar
    CustomRatingBar(
      maxRating: 10,
      iconSize: 32,
      activeColor: Colors.deepOrange,
      inactiveColor: Colors.grey[300],
      allowHalfRating: true,
      showRatingText: true,
      activeIcon: Icons.favorite,
      inactiveIcon: Icons.favorite_border,
      onRatingChanged: (rating) => _updateUserPreference(rating),
    );

    // Read-only display
    CustomRatingBar(
      initialRating: 4.8,
      isInteractive: false,
      allowHalfRating: true,
      activeColor: Colors.amber,
    );
Functional Programming Support

Handle errors and optional values with type-safe functional patterns:

    // Either for error handling
    Either<String, int> parseNumber(String input) {
      try {
        return Either.right(int.parse(input));
      } catch (e) {
        return Either.left('Invalid number: $input');
      }
    }
    
    // Chain operations with flatMap
    final result = parseNumber('42')
        .flatMap((n) => n > 0 ? Either.right(n * 2) : Either.left('Negative'))
        .fold((error) => 'Error: $error', (value) => 'Result: $value');
    
    // Async error handling
    final apiResult = await Either.tryCatchAsync<String, UserData>(
      (error, stackTrace) => 'API Error: ${error.toString()}',
      () => fetchUserData(userId),
    );
    
    // Option for nullable values
    Option<User> findUser(String id) {
      final user = users.firstWhereOrNull((u) => u.id == id);
      return user != null ? Option.some(user) : Option.none();
    }
    
    // Transform optional values
    final greeting = findUser('123')
        .map((user) => 'Hello, ${user.name}!')
        .getOrElse(() => 'User not found');
    
    // Convert between types
    final userEither = findUser('123')
        .toEither(() => 'User not found');
Internet Connectivity
    // Create a checker instance
    final connectionChecker = InternetConnectionChecker();
    
    // Check current connection status
    final isConnected = await connectionChecker.isInternetConnected;
    print('Internet connected: $isConnected');
    
    // Listen to detailed connectivity changes
    connectionChecker.onInternetConnectivityChanged.listen((result) {
      print('Connection Status: ${result.hasInternetAccess}');
      print('Connection Type: ${result.connectionType}');
      
      // Update UI based on connectivity
      if (result.hasInternetAccess) {
        // Load online data
      } else {
        // Show offline mode UI
      }
    });
    
    // Simplified boolean stream for quick status checks
    connectionChecker.onIsInternetConnected.listen((isConnected) {
      print('Internet status changed: $isConnected');
    });
Image Handling
    // Network image with fallback and border radius
    AppImage(
      'https://example.com/profile.jpg',
      width: 150,
      height: 150,
      fit: BoxFit.cover,
      borderRadius: BorderRadius.circular(8),
      backgroundColor: Colors.grey[200],
      errorWidget: Icon(Icons.broken_image),
      fallbackImage: 'assets/default_image.png',
    )
    
    // Circle avatar from network or asset
    AppCircleImage(
      'assets/profile_photo.jpg', // or network URL or File object
      radius: 40,
      fit: BoxFit.cover,
      placeholder: CircularProgressIndicator(strokeWidth: 2),
      errorWidget: Icon(Icons.person),
    )
    
    // As decoration image
    Container(
      decoration: BoxDecoration(
        image: AppImage('https://example.com/bg.jpg')
            .toDecorationImage(
          decorationFit: BoxFit.cover,
          fallbackImage: 'assets/default_bg.png',
        ),
      ),
    )
    
    // Path-based image extensions
    'assets/image.png'.img(width: 100, height: 100)
    'assets/avatar.png'.circleImage(fit: BoxFit.cover)
Animation Utilities
    // Basic fade and scale animation
    AnimatedFadeScale(
      duration: Duration(milliseconds: 500),
      child: Container(
        width: 200,
        height: 200,
        color: Colors.blue,
        child: Center(child: Text('Hello!')),
      ),
    );

    // Staggered animations with delay
    Column(
      children: [
        AnimatedFadeScale(
          delay: Duration(milliseconds: 100),
          child: Card(child: /*...*/),
        ),
        AnimatedFadeScale(
          delay: Duration(milliseconds: 200),
          child: Card(child: /*...*/),
        ),
        AnimatedFadeScale(
          delay: Duration(milliseconds: 300),
          child: Card(child: /*...*/),
        ),
      ],
    );

    // Manual animation control
    double _animationValue = 0.0;

    AnimatedFadeScale(
      value: _animationValue,
      child: FloatingActionButton(
        onPressed: () {
          setState(() {
            _animationValue = _animationValue == 0.0 ? 1.0 : 0.0;
          });
        },
      ),
    );

    // FadeSlideTransition with key-based triggering
    final _transitionKey = UniqueKey();

    FadeSlideTransition(
      transitionKey: _transitionKey,
      duration: Duration(milliseconds: 400),
      initialSlideOffset: Offset(0, 0.1), // Slide up from bottom
      child: _buildContentWidget(),
    );

    // Later when content needs to change
    setState(() {
      _transitionKey = UniqueKey(); // Triggers new transition
    });

    // Using predefined durations
    FadeSlideTransition.fast(
      child: NotificationBadge(count: 5),
    );

    FadeSlideTransition.slow(
      child: HeroImage(url: imageUrl),
    );

    // Transition with completion callback
    FadeSlideTransition(
      child: ProfileHeader(user: user),
      onTransitionComplete: () {
        print('Transition finished!');
      },
    );
PIN Authentication
    PinEntry(
      pinLength: 6,
      onInputComplete: (pin) {
        // Handle PIN validation
      },
      inputFieldConfiguration: InputFieldConfiguration(
        obscureText: true,
        fieldFillColor: Colors.grey[200],
        focusedBorderColor: Colors.blue,
      ),
      keyboardConfiguration: KeyboardConfiguration(
        keyBackgroundColor: Colors.white,
        keyTextStyle: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
      ),
    )
UI Extensions
    // Spacing utilities
    16.spaceX()  // SizedBox(width: 16)
    24.spaceY()  // SizedBox(height: 24)
    32.spaceXY() // SizedBox(width: 32, height: 32)
    
    // Getters for even cleaner code
    20.spX  // SizedBox(width: 20)
    30.spY  // SizedBox(height: 30)
    
    // Custom card with styling
    12.radius(
      child: Padding(
        padding: EdgeInsets.all(16),
        child: Text('Rounded Card Example'),
      ),
      elevation: 2,
      color: Colors.blue[50],
      strokeColor: Colors.black12,
    )
    
    // Text styling
    'Hello Flutter'.edit(
      textStyle: TextStyle(
        fontSize: 20,
        fontWeight: FontWeight.bold,
        color: Colors.teal,
      ),
      textAlign: TextAlign.center,
    )
Logic & Functional Extensions
    // Path extension to transform values
    final doubled = 16.p((n) => n * 2);  // 32
    
    // Widget-friendly conditional logic
    final result = condition(isActive, 'Active', 'Inactive');
    
    // Function-based conditionals (lazy evaluation)
    final message = conditionFunction(
      hasPermission,
      () => 'Access granted',
      () => 'Access denied: ${getErrorMessage()}',
    );
    
    // Safe value retrieval with fallback
    final displayName = get(user.name, 'Guest User');

Advanced Usage

See the API Reference for comprehensive documentation of all available extensions and utilities.

Migration from 1.0.0 to 1.1.0

While version 1.1.0 maintains backward compatibility, we recommend the following changes:

  • Replace assetFallback with fallbackImage parameter in image widgets for improved naming consistency
  • Take advantage of the new File object support in image widgets
  • Utilize new borderRadius and backgroundColor parameters for enhanced customization

Screenshots

(None applicable in this current release)

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/amazing-feature)
  3. Commit your Changes (git commit -m 'Add some amazing feature')
  4. Push to the Branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

This project is licensed under the BSD 3-Clause License - see the LICENSE file for details.

所屬分類

原始碼儲存庫

使用此套件的專案