Skip to content
Haydar Demir

Writing5 min read

Flutter Quick Actions: Handling Multiple Actions with Scalable Code

In this article, we will guide you step by step on how to use quick actions in Flutter to create more user-friendly applications.

A smartphone surrounded by floating Quick Actions icons on a dark background
Created by ChatGPT

Hello Everyone

Nowadays, mobile applications are equipped with constantly evolving technologies to make users’ lives easier. One of these technologies is “quick actions,” which provide shortcuts for fast access to apps directly from the home screen. Flutter offers a powerful tool to integrate this feature into your applications. In this article, we will guide you step by step on how to use quick actions in Flutter to create more user-friendly applications.

What Are Quick Actions?

Quick actions are customizable shortcuts on Android and iOS that allow users to quickly access apps from the home screen. This enables users to reach their most frequently used features with a single tap. For example, a music app might have a “Recently Played” shortcut, while a news app could offer a “Latest News” shortcut.

Why Should We Use Quick Actions?

  • Enhancing User Experience: Quick actions improve usability by allowing users to access your app more quickly.
  • Increasing App Engagement: When users can easily reach frequently used features, they are more likely to engage with the app regularly.
  • Boosting App Visibility: Shortcuts on the home screen help your app stand out among other applications.

Installation:

To use quick actions in Flutter, you need to add the quick_actions package to your project. After adding this package to your pubspec.yaml file and running the flutter pub get command, you can start using it.

dependencies:
  quick_actions: [latest_version]
Interested Look GIF by Anime Crimes Division

QuickActionsClient

QuickActionsClient is an interface used to manage quick actions in your application. This interface allows dependencies to be easily replaced from the outside, helping to create a flexible structure.

The main responsibilities of the interface are:

  • init Used to listen for quick actions and perform initialization processes.
  • checkAndNavigate When the application is first opened, it checks the triggered action and navigates to the relevant page.
  • setShortcutItems Creates and updates quick access shortcuts that appear when the app icon is long-pressed.
  • clearShortcutItems Clears and removes all defined quick access shortcuts.
abstract interface class QuickActionsClient {
  factory QuickActionsClient.instance() => _QuickActionsClientImpl();

  Future<void> init();
  void checkAndNavigate();
  Future<void> setShortcutItems(StoreProjectConfigurationModel storeProjectConfiguration);
  Future<void> clearShortcutItems();
}

final class _QuickActionsClientImpl implements QuickActionsClient {
  final QuickActions _quickActions = const QuickActions();

  late DateTime initTime;
  late DateTime actionTime;
  QuickActionClientType? lastAction;
  QuickActionClientType? initAction;

  final threshold = 2; // Seconds
  final actionIcon = 'quick_actions';

  @override
  Future<void> init() async {
    try {
      initTime = DateTime.now();
      await _quickActions.initialize((String newActionStr) {
        final newAction = QuickActionClientType.fromString(newActionStr);
        if (newAction != null) {
          actionTime = DateTime.now();
          lastAction = newAction;
          _checkLastAction(newAction);
        }
      });
    } catch (e) {
      AppLogger.e(e);
    }
  }

  @override
  void checkAndNavigate() {
    if (initAction != null) {
      PlatformQuickActionNavigator.instance.execute(initAction!, isInitial: true);
      initAction = null;
    }
  }

  @override
  Future<void> setShortcutItems(StoreProjectConfigurationModel storeProjectConfiguration) async {
    try {
      await _quickActions.setShortcutItems(
        <ShortcutItem>[
          ShortcutItem(
            type: QuickActionClientType.home.name,
            localizedTitle: 'Home',
            icon: actionIcon,
          ),
          ShortcutItem(
            type: QuickActionClientType.settings.name,
            localizedTitle: 'Settings',
            icon: actionIcon,
          ),
        ],
      );
    } catch (e) {
      AppLogger.e(e);
    }
  }

  @override
  Future<void> clearShortcutItems() async {
    try {
      await _quickActions.clearShortcutItems();
    } catch (e) {
      AppLogger.e(e);
    }
  }

  void _checkLastAction(QuickActionClientType newAction) {
    final diff = actionTime.difference(initTime).inSeconds;
    if (diff < threshold) {
      // Initial Launch
      initAction = newAction;
    } else {
      // Launched
      PlatformQuickActionNavigator.instance.execute(newAction, isInitial: false);
    }
  }
}

IPlatformQuickAction

The IPlatformQuickAction interface is designed to define a separate action for each type of quick action. This structure is based on the Command Pattern, ensuring that each action operates according to specific criteria.

  • isSatisfiedChecks whether the incoming action meets the specified criteria. The QuickActionClientType type parameter determines for which client type the action is valid.
  • executeExecutes the defined action. The isInitial parameter indicates whether the action is triggered at the initial launch or at a later time.

With this interface, quick action management in your application becomes more flexible and organized. You can define custom actions for different client types, ensuring that each action functions independently within its scope.

Let’s not get hung up on the method names; different names can be used without compromising the overall meaning.

abstract interface class IPlatformQuickAction {
  bool isSatisfied(QuickActionClientType type);
  Future<void> execute({required bool isInitial});
}

QuickActionClientType

QuickActionClientType is an enum structure used to define the types of quick actions supported in your application. This structure helps manage specific action types and determine the appropriate actions to be executed.

  • home Represents a quick action type for the home screen.
  • settings Represents a quick action type for the settings screen.

This enum allows you to manage quick actions in your application within a structured system.

import 'package:collection/collection.dart';

enum QuickActionClientType {
  home,
  settings;

  static QuickActionClientType? fromString(String? value) => QuickActionClientType.values.firstWhereOrNull((element) => element.name == value);
}

HomePlatformQuickAction

HomePlatformQuickAction is an action class designed to open the home screen.

final class HomePlatformQuickAction implements IPlatformQuickAction {
  @override
  bool isSatisfied(QuickActionClientType type) => type == QuickActionClientType.home;

  @override
  Future<void> execute({required bool isInitial}) async {
    unawaited(App.router.push(const HomeGuardRoute()));
  }
}

SettingsPlatformQuickAction

SettingsPlatformQuickAction is an action class designed to open the settings screen.

final class SettingsPlatformQuickAction implements IPlatformQuickAction {
  @override
  bool isSatisfied(QuickActionClientType type) => type == QuickActionClientType.settings;

  @override
  Future<void> execute({required bool isInitial}) async {
    unawaited(App.router.push(const SettingsGuardRoute()));
  }
}

PlatformQuickActionNavigator

PlatformQuickActionNavigator is a central routing structure used for handling quick actions, determining the appropriate action for incoming quick actions and executing the corresponding process.

  • items list contains all the quick actions in the application (e.g., HomePlatformQuickAction, SettingsPlatformQuickAction).
  • execute method checks the incoming quick action type (QuickActionClientType) and executes the appropriate action.

This structure centralizes the management of quick actions, making the code more organized and extensible.

import 'package:collection/collection.dart';
import 'package:fpdart/fpdart.dart' as fpdart;

final class PlatformQuickActionNavigator {
  PlatformQuickActionNavigator._();

  static final PlatformQuickActionNavigator instance = PlatformQuickActionNavigator._();

  final items = <IPlatformQuickAction>[
    HomePlatformQuickAction(),
    SettingsPlatformQuickAction(),
  ];

  Future<void> execute(QuickActionClientType type, {required bool isInitial}) async {
    fpdart.Either.tryCatch(
      () async {
        await items.firstWhereOrNull((element) => element.isSatisfied(type))?.execute(isInitial: isInitial);
      },
      (e, s) => AppLogger.e('PlatformQuickActionNavigator-execute() | Error: $e, StackTrace: $s'),
    );
  }
}

Conclusion

In this article, we explored how to implement quick actions in Flutter to enhance user experience with home screen shortcuts. We introduced a structured approach using the Command Pattern, ensuring flexibility and maintainability.

The QuickActionsClient manages quick actions, while IPlatformQuickAction defines specific actions for different shortcuts. Finally, PlatformQuickActionNavigator centralizes execution, making the system scalable. Implementing quick actions improves usability, increases engagement, and provides a seamless user experience.

Related writing

Type to search