voo_section_list 0.1.0 copy "voo_section_list: ^0.1.0" to clipboard
voo_section_list: ^0.1.0 copied to clipboard

A comprehensive Flutter package for creating settings-style section lists with multiple visual styles, custom builders, and full theming support.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:voo_section_list/voo_section_list.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'VooSectionList Example',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
        useMaterial3: true,
      ),
      darkTheme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.blue,
          brightness: Brightness.dark,
        ),
        useMaterial3: true,
      ),
      home: const StyleSelectorPage(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('VooSectionList Styles'),
      ),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: [
          _StyleCard(
            title: 'Card Style',
            description: 'Elevated cards with rounded corners',
            onTap: () => Navigator.push(
              context,
              MaterialPageRoute(
                builder: (_) => const SettingsPage(style: VooSectionStyle.card),
              ),
            ),
          ),
          const SizedBox(height: 12),
          _StyleCard(
            title: 'iOS Inset Grouped',
            description: 'iOS-style with inset and rounded containers',
            onTap: () => Navigator.push(
              context,
              MaterialPageRoute(
                builder: (_) => const SettingsPage(style: VooSectionStyle.insetGrouped),
              ),
            ),
          ),
          const SizedBox(height: 12),
          _StyleCard(
            title: 'Flat / Material',
            description: 'Android/Material flat style with headers',
            onTap: () => Navigator.push(
              context,
              MaterialPageRoute(
                builder: (_) => const SettingsPage(style: VooSectionStyle.flat),
              ),
            ),
          ),
          const SizedBox(height: 12),
          _StyleCard(
            title: 'Plain',
            description: 'Minimal plain list with dividers',
            onTap: () => Navigator.push(
              context,
              MaterialPageRoute(
                builder: (_) => const SettingsPage(style: VooSectionStyle.plain),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

class _StyleCard extends StatelessWidget {
  final String title;
  final String description;
  final VoidCallback onTap;

  const _StyleCard({
    required this.title,
    required this.description,
    required this.onTap,
  });

  @override
  Widget build(BuildContext context) {
    return Card(
      child: ListTile(
        title: Text(title),
        subtitle: Text(description),
        trailing: const Icon(Icons.chevron_right),
        onTap: onTap,
      ),
    );
  }
}

class SettingsPage extends StatefulWidget {
  final VooSectionStyle style;

  const SettingsPage({super.key, required this.style});

  @override
  State<SettingsPage> createState() => _SettingsPageState();
}

class _SettingsPageState extends State<SettingsPage> {
  bool _notificationsEnabled = true;
  bool _emailUpdates = false;
  bool _darkMode = false;
  bool _autoplay = true;
  bool _downloadWifiOnly = true;
  String _language = 'English';
  String _theme = 'System';

  VooSectionConfig get _config {
    switch (widget.style) {
      case VooSectionStyle.card:
        return VooSectionConfig.card;
      case VooSectionStyle.insetGrouped:
        return VooSectionConfig.ios;
      case VooSectionStyle.flat:
        return VooSectionConfig.material;
      case VooSectionStyle.plain:
        return VooSectionConfig.plain;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('${widget.style.displayName} Style'),
      ),
      body: VooSectionList<void>(
        config: _config,
        padding: const EdgeInsets.symmetric(vertical: 8),
        sections: [
          VooSection(
            id: 'account',
            title: 'Account',
            items: [
              VooSectionItem(
                id: 'profile',
                title: 'Edit Profile',
                leading: const Icon(Icons.person_outline),
                type: VooSectionItemType.navigation,
                onTap: () => _showSnackBar('Edit Profile tapped'),
              ),
              VooSectionItem(
                id: 'password',
                title: 'Change Password',
                leading: const Icon(Icons.lock_outline),
                type: VooSectionItemType.navigation,
                onTap: () => _showSnackBar('Change Password tapped'),
              ),
            ],
          ),
          VooSection(
            id: 'notifications',
            title: 'Notifications',
            items: [
              VooSectionItem(
                id: 'push',
                title: 'Push Notifications',
                leading: const Icon(Icons.notifications_outlined),
                type: VooSectionItemType.toggle,
                toggleValue: _notificationsEnabled,
                onToggleChanged: (value) {
                  setState(() => _notificationsEnabled = value);
                },
              ),
              VooSectionItem(
                id: 'email',
                title: 'Email Updates',
                leading: const Icon(Icons.email_outlined),
                type: VooSectionItemType.toggle,
                toggleValue: _emailUpdates,
                onToggleChanged: (value) {
                  setState(() => _emailUpdates = value);
                },
              ),
            ],
          ),
          VooSection(
            id: 'preferences',
            title: 'Preferences',
            footerText: 'Choose your preferred display settings',
            items: [
              VooSectionItem(
                id: 'language',
                title: 'Language',
                leading: const Icon(Icons.language),
                type: VooSectionItemType.value,
                displayValue: _language,
                onTap: () => _showLanguagePicker(),
              ),
              VooSectionItem(
                id: 'theme',
                title: 'Theme',
                leading: const Icon(Icons.palette_outlined),
                type: VooSectionItemType.value,
                displayValue: _theme,
                onTap: () => _showThemePicker(),
              ),
              VooSectionItem(
                id: 'darkMode',
                title: 'Dark Mode',
                leading: const Icon(Icons.dark_mode_outlined),
                type: VooSectionItemType.toggle,
                toggleValue: _darkMode,
                onToggleChanged: (value) {
                  setState(() => _darkMode = value);
                },
              ),
            ],
          ),
          VooSection(
            id: 'playback',
            title: 'Playback',
            items: [
              VooSectionItem(
                id: 'autoplay',
                title: 'Autoplay',
                subtitle: 'Automatically play next video',
                leading: const Icon(Icons.play_circle_outline),
                type: VooSectionItemType.toggle,
                toggleValue: _autoplay,
                onToggleChanged: (value) {
                  setState(() => _autoplay = value);
                },
              ),
              VooSectionItem(
                id: 'wifiOnly',
                title: 'Download via WiFi only',
                leading: const Icon(Icons.wifi),
                type: VooSectionItemType.toggle,
                toggleValue: _downloadWifiOnly,
                onToggleChanged: (value) {
                  setState(() => _downloadWifiOnly = value);
                },
              ),
            ],
          ),
          VooSection(
            id: 'about',
            title: 'About',
            items: [
              VooSectionItem(
                id: 'version',
                title: 'Version',
                leading: const Icon(Icons.info_outline),
                type: VooSectionItemType.info,
                trailing: Text(
                  '1.0.0',
                  style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant),
                ),
              ),
              VooSectionItem(
                id: 'terms',
                title: 'Terms of Service',
                leading: const Icon(Icons.description_outlined),
                type: VooSectionItemType.navigation,
                onTap: () => _showSnackBar('Terms of Service tapped'),
              ),
              VooSectionItem(
                id: 'privacy',
                title: 'Privacy Policy',
                leading: const Icon(Icons.privacy_tip_outlined),
                type: VooSectionItemType.navigation,
                onTap: () => _showSnackBar('Privacy Policy tapped'),
              ),
            ],
          ),
          VooSection(
            id: 'danger',
            title: 'Danger Zone',
            items: [
              VooSectionItem(
                id: 'logout',
                title: 'Sign Out',
                leading: const Icon(Icons.logout),
                type: VooSectionItemType.destructive,
                onTap: () => _showSignOutDialog(),
              ),
              VooSectionItem(
                id: 'delete',
                title: 'Delete Account',
                leading: const Icon(Icons.delete_forever),
                type: VooSectionItemType.destructive,
                onTap: () => _showDeleteDialog(),
              ),
            ],
          ),
        ],
      ),
    );
  }

  void _showSnackBar(String message) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text(message)),
    );
  }

  void _showLanguagePicker() {
    showModalBottomSheet(
      context: context,
      builder: (context) => Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          ListTile(
            title: const Text('English'),
            trailing: _language == 'English' ? const Icon(Icons.check) : null,
            onTap: () {
              setState(() => _language = 'English');
              Navigator.pop(context);
            },
          ),
          ListTile(
            title: const Text('Spanish'),
            trailing: _language == 'Spanish' ? const Icon(Icons.check) : null,
            onTap: () {
              setState(() => _language = 'Spanish');
              Navigator.pop(context);
            },
          ),
          ListTile(
            title: const Text('French'),
            trailing: _language == 'French' ? const Icon(Icons.check) : null,
            onTap: () {
              setState(() => _language = 'French');
              Navigator.pop(context);
            },
          ),
          const SizedBox(height: 16),
        ],
      ),
    );
  }

  void _showThemePicker() {
    showModalBottomSheet(
      context: context,
      builder: (context) => Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          ListTile(
            title: const Text('System'),
            trailing: _theme == 'System' ? const Icon(Icons.check) : null,
            onTap: () {
              setState(() => _theme = 'System');
              Navigator.pop(context);
            },
          ),
          ListTile(
            title: const Text('Light'),
            trailing: _theme == 'Light' ? const Icon(Icons.check) : null,
            onTap: () {
              setState(() => _theme = 'Light');
              Navigator.pop(context);
            },
          ),
          ListTile(
            title: const Text('Dark'),
            trailing: _theme == 'Dark' ? const Icon(Icons.check) : null,
            onTap: () {
              setState(() => _theme = 'Dark');
              Navigator.pop(context);
            },
          ),
          const SizedBox(height: 16),
        ],
      ),
    );
  }

  void _showSignOutDialog() {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('Sign Out'),
        content: const Text('Are you sure you want to sign out?'),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('Cancel'),
          ),
          TextButton(
            onPressed: () {
              Navigator.pop(context);
              _showSnackBar('Signed out');
            },
            child: const Text('Sign Out'),
          ),
        ],
      ),
    );
  }

  void _showDeleteDialog() {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('Delete Account'),
        content: const Text(
          'This action cannot be undone. All your data will be permanently deleted.',
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('Cancel'),
          ),
          TextButton(
            onPressed: () {
              Navigator.pop(context);
              _showSnackBar('Account deleted');
            },
            style: TextButton.styleFrom(foregroundColor: Colors.red),
            child: const Text('Delete'),
          ),
        ],
      ),
    );
  }
}
0
likes
160
points
111
downloads

Publisher

verified publishervoostack.com

Weekly Downloads

A comprehensive Flutter package for creating settings-style section lists with multiple visual styles, custom builders, and full theming support.

Homepage
Repository (GitHub)
View/report issues

Topics

#flutter #settings #lists #user-interface #section-list

Documentation

API reference

License

MIT (license)

Dependencies

equatable, flutter, voo_responsive, voo_tokens, voo_ui_core

More

Packages that depend on voo_section_list