flutter_adaptive_assist 1.0.0 copy "flutter_adaptive_assist: ^1.0.0" to clipboard
flutter_adaptive_assist: ^1.0.0 copied to clipboard

This package provides a cohesive, cross-platform API for developers to listen to, react to, and utilize high-level user-defined system settings and less-common device sensors to create truly adaptive UI/UX.

Flutter Adaptive Assist #

A Flutter plugin that provides unified access to platform-specific accessibility settings, enabling developers to create truly adaptive user interfaces that respect system accessibility preferences.

Features #

  • ๐ŸŽจ Monochrome Mode Detection - Detect when users have enabled grayscale/color correction
  • ๐ŸŽฌ Reduce Motion Support - Respond to user preferences for reduced animations
  • ๐Ÿ“ Bold Text Detection - Identify when users prefer bold text (iOS)
  • ๐ŸŒ— High Contrast Mode - Detect high contrast preferences
  • ๐Ÿ“ Text Scale Factor - Access the system's text size multiplier
  • ๐Ÿ“ก Reactive Streams - Listen to real-time changes in accessibility settings
  • ๐Ÿ”’ Type-Safe - Full null-safety support
  • ๐Ÿงช Testable - Built with testing in mind

Platform Support #

Feature Android iOS
Monochrome Mode โœ… (API 21+) โœ… (iOS 13.0+)
Reduce Motion โœ… (API 21+) โœ… (iOS 13.0+)
Bold Text โŒ โœ… (iOS 13.0+)
High Contrast โœ… (API 21+) โœ… (iOS 13.0+)
Text Scale Factor โœ… (API 21+) โœ… (iOS 13.0+)

Installation #

Add this to your package's pubspec.yaml file:

dependencies:
  flutter_adaptive_assist: ^1.0.0

Then run:

flutter pub get

Usage #

Basic Setup #

Initialize the plugin early in your app (e.g., in main()):

import 'package:flutter_adaptive_assist/adaptive_assist.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  AdaptiveAssist.ensureInitialized();
  runApp(MyApp());
}

Check Current Settings #

// Check individual settings
final isMonochrome = await AdaptiveAssist.getMonochromeModeEnabled();

if (isMonochrome) {
  // Apply monochrome-friendly color scheme
}

// Or get all settings at once (more efficient)
final config = await AdaptiveAssist.getConfig();

if (config.monochromeModeEnabled) {
  // Apply monochrome-friendly colors
}

if (config.reduceMotionEnabled) {
  // Disable or simplify animations
}

if (config.textScaleFactor > 1.5) {
  // Adjust layout for larger text
}

Listen to Changes #

@override
void initState() {
  super.initState();
  
  // Listen to monochrome mode changes
  AdaptiveAssist.monochromeModeEnabledStream.listen((isEnabled) {
    setState(() {
      _isMonochrome = isEnabled;
    });
  });
}

Complete Example #

import 'package:flutter/material.dart';
import 'package:flutter_adaptive_assist/adaptive_assist.dart';

class AdaptiveHomePage extends StatefulWidget {
  @override
  _AdaptiveHomePageState createState() => _AdaptiveHomePageState();
}

class _AdaptiveHomePageState extends State<AdaptiveHomePage> {
  AdaptiveConfig _config = AdaptiveConfig();

  @override
  void initState() {
    super.initState();
    _loadConfig();
    
    // Listen to changes
    AdaptiveAssist.monochromeModeEnabledStream.listen((enabled) {
      _loadConfig();
    });
  }

  Future<void> _loadConfig() async {
    final config = await AdaptiveAssist.getConfig();
    setState(() {
      _config = config;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Adaptive UI Demo'),
      ),
      body: AnimatedContainer(
        duration: _config.reduceMotionEnabled 
            ? Duration.zero 
            : Duration(milliseconds: 300),
        color: _config.monochromeModeEnabled 
            ? Colors.grey[300] 
            : Colors.blue[100],
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(
                'Accessibility Status',
                style: TextStyle(
                  fontSize: 20 * _config.textScaleFactor,
                  fontWeight: _config.boldTextEnabled 
                      ? FontWeight.bold 
                      : FontWeight.normal,
                ),
              ),
              SizedBox(height: 20),
              _buildStatusCard('Monochrome Mode', _config.monochromeModeEnabled),
              _buildStatusCard('Reduce Motion', _config.reduceMotionEnabled),
              _buildStatusCard('Bold Text', _config.boldTextEnabled),
              _buildStatusCard('High Contrast', _config.highContrastEnabled),
              _buildStatusCard('Text Scale', '${_config.textScaleFactor.toStringAsFixed(2)}x'),
            ],
          ),
        ),
      ),
    );
  }

  Widget _buildStatusCard(String label, dynamic value) {
    return Card(
      margin: EdgeInsets.symmetric(horizontal: 20, vertical: 8),
      child: Padding(
        padding: EdgeInsets.all(16),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Text(label),
            Text(
              value.toString(),
              style: TextStyle(fontWeight: FontWeight.bold),
            ),
          ],
        ),
      ),
    );
  }

  @override
  void dispose() {
    // Optional: dispose if you want to clean up
    // AdaptiveAssist.dispose();
    super.dispose();
  }
}

API Reference #

AdaptiveAssist #

Methods

  • static void ensureInitialized() - Initialize the plugin (safe to call multiple times)
  • static Future<bool> getMonochromeModeEnabled() - Check if monochrome mode is enabled
  • static Future<AdaptiveConfig> getConfig() - Get all accessibility settings at once
  • static void clearCache() - Force fresh platform queries on next call
  • static void dispose() - Clean up resources (typically called on app disposal)

Streams

  • static Stream<bool> monochromeModeEnabledStream - Stream of monochrome mode changes

AdaptiveConfig #

A data class containing all accessibility settings:

class AdaptiveConfig {
  final bool reduceMotionEnabled;
  final bool monochromeModeEnabled;
  final bool boldTextEnabled;
  final bool highContrastEnabled;
  final double textScaleFactor;
}

Testing #

The plugin is designed to be testable. Use the provided test channel for unit tests:

import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_adaptive_assist/adaptive_assist.dart';

void main() {
  setUp(() {
    AdaptiveAssist.reset();
    
    // Set up mock channel
    final testChannel = MethodChannel('flutter_adaptive_assist');
    AdaptiveAssist.testChannel = testChannel;
    
    // Mock responses
    TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
        .setMockMethodCallHandler(testChannel, (call) async {
      if (call.method == 'getMonochromeModeEnabled') {
        return true;
      }
      return null;
    });
  });

  test('getMonochromeModeEnabled returns mocked value', () async {
    final result = await AdaptiveAssist.getMonochromeModeEnabled();
    expect(result, true);
  });
}

Platform-Specific Notes #

Android #

  • Monochrome Mode: Checks both Color Correction (Daltonizer) and Color Inversion settings
  • Reduce Motion: Checks if animation scales are set to very low values (< 0.1)
  • Bold Text: Not available system-wide on Android (returns false)
  • High Contrast: Available on Android 5.0+ (API 21)
  • Minimum SDK: API 21 (Android 5.0 Lollipop)

iOS #

  • Monochrome Mode: Uses UIAccessibility.isGrayscaleEnabled
  • Reduce Motion: Uses UIAccessibility.isReduceMotionEnabled
  • Bold Text: Uses UIAccessibility.isBoldTextEnabled
  • High Contrast: Uses UIAccessibility.isDarkerSystemColorsEnabled (iOS 13.0+)
  • Text Scale Factor: Maps UIApplication.shared.preferredContentSizeCategory to numeric values
  • Minimum Version: iOS 13.0

Performance Considerations #

  • The plugin caches values to minimize platform calls
  • Cache is automatically updated when settings change
  • Use getConfig() instead of multiple individual calls when you need several values
  • Streams are broadcast streams - safe to have multiple listeners

Troubleshooting #

Stream not emitting values #

Make sure you call AdaptiveAssist.ensureInitialized() before subscribing to streams.

Values not updating on Android #

Check that your app has the necessary permissions and that ContentObserver registration succeeded (check logs).

iOS notifications not working #

Ensure you're testing on a real device, as some accessibility features may not work correctly in the simulator.

Contributing #

Contributions are welcome! Please read the contributing guidelines before submitting PRs.

License #

This project is licensed under the MIT License - see the LICENSE file for details.

Credits #

Developed with โค๏ธ for the Flutter community.

0
likes
140
points
0
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

This package provides a cohesive, cross-platform API for developers to listen to, react to, and utilize high-level user-defined system settings and less-common device sensors to create truly adaptive UI/UX.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on flutter_adaptive_assist

Packages that implement flutter_adaptive_assist