simple_controller 1.5.0 copy "simple_controller: ^1.5.0" to clipboard
simple_controller: ^1.5.0 copied to clipboard

A lightweight and efficient state management solution for Flutter applications.

example/lib/main.dart

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

enum Env {
  dev,
  uat,
  stg,
  prod,
}

class SettingController extends SimpleController {
  late final localeState = createState(Locale('en', 'US'));
  late final themeModeState = createState(ThemeMode.system);
  late final envState = createState(
    Env.dev,
    listen: (prev, next) {
      themeModeState.value = switch (next) {
        Env.dev => ThemeMode.light,
        Env.uat => ThemeMode.dark,
        Env.stg => ThemeMode.system,
        Env.prod => ThemeMode.system,
      };
    },
  );
}

class MainAppController extends SimpleController {
  MainAppController({
    required SettingController settingController,
  }) {
    addDependency(
      controller: settingController,
      select: (value) => value.envState.value,
      listen: (prev, next) {
        countLengthState.value = switch (next) {
          Env.dev => 3,
          Env.uat => 2,
          Env.stg => 1,
          Env.prod => 0,
        };
      },
    );
  }

  late final countLengthState = createState(0);

  final int maxCountLength = 3;

  bool get isMaxCountLength => countLengthState.value >= maxCountLength;

  bool get isMinCountLength => countLengthState.value <= 0;

  late final incrementCountLength = createCommand((_) {
    if (isMaxCountLength) {
      return;
    }
    countLengthState.value++;
  });

  late final decrementCountLength = createCommand((_) {
    if (isMinCountLength) {
      return;
    }
    countLengthState.value--;
  });
}

class HomePageController extends SimpleController {
  HomePageController({
    required MainAppController mainAppController,
  }) {
    addDependency(
      controller: mainAppController,
      select: (value) => value.countLengthState.value,
      listen: (prev, next) {
        countsState.value = List.generate(
          next,
          (i) => countsState.value.elementAtOrNull(i) ?? 0,
        );
      },
    );
  }

  late final countsState = createState(<int>[]);

  late final increment = createCommand(
    (int index) {
      countsState.value[index]++;
    },
    debounce: const Duration(milliseconds: 100),
  );
}

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

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

  @override
  Widget build(BuildContext context) {
    return SimpleControllerProvider.multi(
      providers: [
        SimpleControllerProvider<SettingController>(
          create: (context) => SettingController(),
        ),
        SimpleControllerProvider<MainAppController>(
          create: (context) => MainAppController(
            settingController: context.use(),
          ),
        ),
      ],
      child: Builder(
        builder: (context) {
          final settingController = context.use<SettingController>();

          return settingController.build(
            select: (value) => (
              locale: value.localeState.value,
              themeMode: value.themeModeState.value,
            ),
            builder: (context, value, child) => MaterialApp(
              locale: value.locale,
              themeMode: value.themeMode,
              theme: ThemeData.light(),
              darkTheme: ThemeData.dark(),
              home: child,
            ),
            child: SimpleControllerProvider(
              create: (context) => HomePageController(
                mainAppController: context.use(),
              ),
              child: HomePage(),
            ),
          );
        },
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    final controller = context.use<HomePageController>();

    return Scaffold(
      appBar: AppBar(
        title: Text('Home'),
        actions: [
          SettingWidget(),
          SizedBox(width: 8.0),
        ],
      ),
      body: Center(
        child: controller.build(
          select: (value) => value.countsState.value.length,
          builder: (context, length, child) => Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              for (var i = 0; i < length; i++) ...[
                if (i > 0) const SizedBox(height: 8.0),
                controller.build(
                  select: (value) => value.countsState.value.elementAtOrNull(i),
                  builder: (context, value, child) {
                    return Text('count${i + 1}: $value');
                  },
                ),
              ],
              const SizedBox(height: 8.0),
              MainWidget(),
            ],
          ),
        ),
      ),
      floatingActionButton: controller.build(
        select: (value) => value.countsState.value.length,
        builder: (context, length, child) {
          return Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              for (var i = 0; i < length; i++) ...[
                if (i > 0) const SizedBox(height: 8.0),
                FilledButton.icon(
                  onPressed: () {
                    controller.increment.execute(i);
                  },
                  icon: Icon(Icons.add),
                  label: Text('count${i + 1}'),
                ),
              ],
            ],
          );
        },
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    final controller = context.use<SettingController>();
    return Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        controller.build(
          select: (value) => value.themeModeState.value,
          builder: (context, themeMode, child) {
            return DropdownButton(
              value: themeMode,
              items: [
                for (final value in ThemeMode.values)
                  DropdownMenuItem(
                    value: value,
                    child: Text(value.name),
                  ),
              ],
              onChanged: (value) {
                if (value != null) {
                  controller.themeModeState.value = value;
                }
              },
            );
          },
        ),
        SizedBox(width: 8.0),
        controller.build(
          select: (value) => value.envState.value,
          builder: (context, env, child) {
            return DropdownButton(
              value: env,
              items: [
                for (final value in Env.values)
                  DropdownMenuItem(
                    value: value,
                    child: Text(value.name),
                  ),
              ],
              onChanged: (value) {
                if (value != null) {
                  controller.envState.value = value;
                }
              },
            );
          },
        ),
      ],
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    final controller = context.use<MainAppController>();
    return Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        controller.build(
          select: (value) => value.isMinCountLength,
          builder: (context, isMinCountLength, child) => controller.build(
            select: (value) => value.decrementCountLength.isExecuting,
            builder: (context, isExecuting, child) => IconButton(
              onPressed: isMinCountLength || isExecuting
                  ? null
                  : () {
                      controller.decrementCountLength.execute(null);
                    },
              icon: Icon(Icons.remove),
            ),
          ),
        ),
        SizedBox(width: 8.0),
        controller.build(
          select: (value) => value.isMaxCountLength,
          builder: (context, isMaxCountLength, child) => controller.build(
            select: (value) => value.incrementCountLength.isExecuting,
            builder: (context, isExecuting, child) => IconButton(
              onPressed: isMaxCountLength || isExecuting
                  ? null
                  : () {
                      controller.incrementCountLength.execute(null);
                    },
              icon: Icon(Icons.add),
            ),
          ),
        ),
      ],
    );
  }
}
3
likes
160
points
45
downloads

Publisher

unverified uploader

Weekly Downloads

A lightweight and efficient state management solution for Flutter applications.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

flutter

More

Packages that depend on simple_controller