Skip to main content

flutter_second_screen 1.0.1 copy "flutter_second_screen: ^1.0.1" to clipboard
flutter_second_screen: ^1.0.1 copied to clipboard

A clean architecture Flutter package for managing secondary screens and cross-screen communication on Windows and macOS desktop, with upcoming Android and iOS support.

Flutter Second Screen #

A production-grade, Clean Architecture Flutter package for managing secondary screens, dual displays, and cross-screen communication. Currently available for Windows Desktop, with architectural blueprints and upcoming native support for Android and iOS.


๐ŸŒŸ Key Features #

  • Multi-Display Detection: Query physical monitors, detect primary vs. secondary displays, resolutions, and position offsets.
  • Secondary Window Lifecycle: Initialize, open, maximize, focus, and close secondary windows seamlessly.
  • Bi-Directional Messaging: Typed or event-based cross-screen event bus to transfer cart data, signatures, advertisements, or status updates between windows.
  • Clean Architecture & SOLID: Strict separation of concerns (Domain, Data, Presentation) with dependency inversion, interface segregation, and platform interface extensibility.
  • Developer-Friendly Mixin & Widgets: Use SecondScreenListenerMixin, SecondScreenEventListener, or SecondScreenEventBuilder for reactive UI updates without boilerplate.
  • Multi-Platform Blueprint: Built on Flutter's PlatformInterface standard with pluggable platform classes and documented TODO blueprints for Android Presentation API and iOS external UIScreen.

๐Ÿ–ฅ Platform Support #

Platform Support Status Underlying Mechanism
Windows Desktop / macOS โœ… Available window_manager_plus + screen_retriever multi-window
Android โณ In Development android.app.Presentation + DisplayManager
iOS โณ In Development UIScreen external displays + UIWindow
Linux ๐Ÿ“‹ Planned Desktop multi-window & display retriever

๐Ÿ› Architecture Overview #

flutter_second_screen strictly adheres to Clean Architecture and SOLID principles, ensuring decoupling between UI, business rules, and platform-specific window managers.

๐ŸŒณ Architectural Component Tree #

flutter_second_screen
โ”œโ”€โ”€ ๐Ÿ“ฑ Presentation Layer (Flutter Widgets & Mixins)
โ”‚   โ”œโ”€โ”€ Main Screen View (Cashier / POS UI)
โ”‚   โ”œโ”€โ”€ Secondary Screen View (Customer Display UI)
โ”‚   โ”œโ”€โ”€ SecondScreenListenerMixin (State mixin for reactive events)
โ”‚   โ”œโ”€โ”€ SecondScreenEventListener (Callback-based event listener widget)
โ”‚   โ””โ”€โ”€ SecondScreenEventBuilder (Builder widget reacting to stream events)
โ”‚
โ”œโ”€โ”€ ๐ŸŽฏ Unified Facade (Public API Entry Point)
โ”‚   โ””โ”€โ”€ FlutterSecondScreen (Singleton & factory for all operations)
โ”‚
โ”œโ”€โ”€ ๐Ÿง  Domain Layer (Pure Dart Business Logic - Zero External Dependencies)
โ”‚   โ”œโ”€โ”€ ๐Ÿ“ฆ Entities
โ”‚   โ”‚   โ”œโ”€โ”€ ScreenDisplay (Display ID, resolution, position offset, isPrimary)
โ”‚   โ”‚   โ”œโ”€โ”€ SecondScreenEvent<T> (Cross-screen typed messaging model)
โ”‚   โ”‚   โ”œโ”€โ”€ SecondScreenConfig (Secondary window title, size, position, flags)
โ”‚   โ”‚   โ””โ”€โ”€ SecondScreenStatus (Window lifecycle state)
โ”‚   โ”‚
โ”‚   โ”œโ”€โ”€ โš™๏ธ Use Cases (Single Responsibility)
โ”‚   โ”‚   โ”œโ”€โ”€ Display Management
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ GetDisplaysUseCase
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ IsSecondaryDisplayAvailableUseCase
โ”‚   โ”‚   โ”œโ”€โ”€ Window Lifecycle
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ InitSecondaryDisplayUseCase
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ OpenSecondaryScreenUseCase
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ CloseSecondaryScreenUseCase
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ IsSecondaryScreenOpenUseCase
โ”‚   โ”‚   โ””โ”€โ”€ Cross-Screen Messaging
โ”‚   โ”‚       โ”œโ”€โ”€ SendEventToSecondaryUseCase
โ”‚   โ”‚       โ”œโ”€โ”€ SendEventToMainUseCase
โ”‚   โ”‚       โ””โ”€โ”€ ListenSecondaryScreenEventsUseCase
โ”‚   โ”‚
โ”‚   โ””โ”€โ”€ ๐Ÿ“‹ Repository Contracts (Interface Segregation)
โ”‚       โ”œโ”€โ”€ SecondScreenDisplayManager (Display detection contract)
โ”‚       โ”œโ”€โ”€ SecondScreenWindowManager (Window lifecycle contract)
โ”‚       โ”œโ”€โ”€ SecondScreenMessenger (Cross-screen messaging contract)
โ”‚       โ””โ”€โ”€ SecondScreenRepository (Aggregated domain interface)
โ”‚
โ””โ”€โ”€ ๐Ÿ’พ Data Layer (Infrastructure & Platform Implementations)
    โ”œโ”€โ”€ ๐Ÿ”„ Repository Implementation
    โ”‚   โ””โ”€โ”€ SecondScreenRepositoryImpl (Implements Domain Repository via DIP)
    โ”‚
    โ”œโ”€โ”€ ๐Ÿ“ฆ Data Models (Adapters & Serialization)
    โ”‚   โ”œโ”€โ”€ ScreenDisplayModel (Adapts platform displays to domain entities)
    โ”‚   โ””โ”€โ”€ SecondScreenEventModel (JSON serialization for cross-screen events)
    โ”‚
    โ””โ”€โ”€ ๐Ÿ”Œ Platform Data Sources (Platform Interface Pattern)
        โ””โ”€โ”€ SecondScreenPlatform (Federated platform interface)
            โ”œโ”€โ”€ DesktopSecondScreenPlatform (Windows & macOS multi-window core)
            โ”‚   โ”œโ”€โ”€ WindowsSecondScreenPlatform (Windows desktop plugin class)
            โ”‚   โ””โ”€โ”€ MacosSecondScreenPlatform (macOS desktop plugin class)
            โ”œโ”€โ”€ AndroidSecondScreenPlatform (Android Presentation API blueprint)
            โ””โ”€โ”€ IosSecondScreenPlatform (iOS UIScreen & UIWindow blueprint)

๐Ÿ“‚ Codebase File & Folder Structure #

lib/
โ”œโ”€โ”€ flutter_second_screen.dart             # Public export library entrypoint
โ””โ”€โ”€ src/
    โ”œโ”€โ”€ flutter_second_screen.dart         # FlutterSecondScreen facade class
    โ”œโ”€โ”€ presentation/                      # Presentation Layer
    โ”‚   โ”œโ”€โ”€ presentation.dart
    โ”‚   โ”œโ”€โ”€ mixins/
    โ”‚   โ”‚   โ””โ”€โ”€ second_screen_listener_mixin.dart
    โ”‚   โ””โ”€โ”€ widgets/
    โ”‚       โ””โ”€โ”€ second_screen_event_listener.dart
    โ”œโ”€โ”€ domain/                            # Domain Layer (Pure Dart)
    โ”‚   โ”œโ”€โ”€ domain.dart
    โ”‚   โ”œโ”€โ”€ entities/
    โ”‚   โ”‚   โ”œโ”€โ”€ entities.dart
    โ”‚   โ”‚   โ”œโ”€โ”€ screen_display.dart
    โ”‚   โ”‚   โ”œโ”€โ”€ second_screen_config.dart
    โ”‚   โ”‚   โ”œโ”€โ”€ second_screen_event.dart
    โ”‚   โ”‚   โ””โ”€โ”€ second_screen_status.dart
    โ”‚   โ”œโ”€โ”€ repositories/
    โ”‚   โ”‚   โ”œโ”€โ”€ repositories.dart
    โ”‚   โ”‚   โ”œโ”€โ”€ second_screen_display_manager.dart
    โ”‚   โ”‚   โ”œโ”€โ”€ second_screen_window_manager.dart
    โ”‚   โ”‚   โ”œโ”€โ”€ second_screen_messenger.dart
    โ”‚   โ”‚   โ””โ”€โ”€ second_screen_repository.dart
    โ”‚   โ””โ”€โ”€ usecases/
    โ”‚       โ”œโ”€โ”€ usecases.dart
    โ”‚       โ”œโ”€โ”€ get_displays_usecase.dart
    โ”‚       โ”œโ”€โ”€ is_secondary_display_available_usecase.dart
    โ”‚       โ”œโ”€โ”€ init_secondary_display_usecase.dart
    โ”‚       โ”œโ”€โ”€ open_secondary_screen_usecase.dart
    โ”‚       โ”œโ”€โ”€ close_secondary_screen_usecase.dart
    โ”‚       โ”œโ”€โ”€ is_secondary_screen_open_usecase.dart
    โ”‚       โ”œโ”€โ”€ send_event_to_secondary_usecase.dart
    โ”‚       โ”œโ”€โ”€ send_event_to_main_usecase.dart
    โ”‚       โ””โ”€โ”€ listen_secondary_screen_events_usecase.dart
    โ””โ”€โ”€ data/                              # Data Layer
        โ”œโ”€โ”€ data.dart
        โ”œโ”€โ”€ datasources/
        โ”‚   โ”œโ”€โ”€ datasources.dart
        โ”‚   โ”œโ”€โ”€ second_screen_platform.dart
        โ”‚   โ”œโ”€โ”€ desktop_second_screen_platform.dart
        โ”‚   โ”œโ”€โ”€ windows_second_screen_platform.dart
        โ”‚   โ”œโ”€โ”€ macos_second_screen_platform.dart
        โ”‚   โ”œโ”€โ”€ android_second_screen_platform.dart
        โ”‚   โ””โ”€โ”€ ios_second_screen_platform.dart
        โ”œโ”€โ”€ models/
        โ”‚   โ”œโ”€โ”€ models.dart
        โ”‚   โ”œโ”€โ”€ screen_display_model.dart
        โ”‚   โ””โ”€โ”€ second_screen_event_model.dart
        โ””โ”€โ”€ repositories/
            โ”œโ”€โ”€ repositories.dart
            โ””โ”€โ”€ second_screen_repository_impl.dart

๐Ÿ”„ Data & Control Flow Diagram #

flowchart TD
    subgraph UI ["Presentation Layer (Flutter UI)"]
        ScreenA["Main Screen View"]
        ScreenB["Secondary Screen View"]
        Mixin["SecondScreenListenerMixin"]
        Widget["SecondScreenEventListener"]
    end

    subgraph Facade ["Unified Facade"]
        FSS["FlutterSecondScreen"]
    end

    subgraph Domain ["Domain Layer (Pure Dart)"]
        direction TB
        UseCases["Use Cases (Open, Close, Init, SendEvent, etc.)"]
        Contracts["Repository Contracts (DisplayManager, WindowManager, Messenger)"]
        Entities["Entities (ScreenDisplay, SecondScreenEvent, SecondScreenConfig)"]
        UseCases --> Contracts
        UseCases -.-> Entities
    end

    subgraph Data ["Data Layer"]
        RepoImpl["SecondScreenRepositoryImpl"]
        PI["SecondScreenPlatform (Interface)"]
        
        subgraph Implementations ["Platform Drivers"]
            DeskPlat["DesktopSecondScreenPlatform"]
            WinPlat["WindowsSecondScreenPlatform"]
            MacPlat["MacosSecondScreenPlatform"]
            AndPlat["AndroidSecondScreenPlatform (Blueprint)"]
            IosPlat["IosSecondScreenPlatform (Blueprint)"]
        end
    end

    UI --> Facade
    Facade --> UseCases
    RepoImpl -.->|implements (DIP)| Contracts
    RepoImpl --> PI
    PI --> DeskPlat
    DeskPlat --> WinPlat
    DeskPlat --> MacPlat
    PI --> AndPlat
    PI --> IosPlat

SOLID Principles Applied: #

  • Single Responsibility Principle (SRP): Display queries (SecondScreenDisplayManager), window lifecycle management (SecondScreenWindowManager), and inter-screen messaging (SecondScreenMessenger) are decoupled into focused, dedicated interfaces.
  • Open/Closed Principle (OCP): Adding support for a new operating system (e.g., Android, iOS, or macOS) only requires implementing SecondScreenPlatform without modifying the domain use cases or repository contracts.
  • Liskov Substitution Principle (LSP): Any platform implementation (WindowsSecondScreenPlatform, AndroidSecondScreenPlatform, or test mocks) can be seamlessly substituted without breaking consumers.
  • Interface Segregation Principle (ISP): Clients can depend solely on SecondScreenDisplayManager, SecondScreenWindowManager, or SecondScreenMessenger instead of one monolithic interface.
  • Dependency Inversion Principle (DIP): High-level application modules depend on domain abstractions rather than concrete platform libraries.

๐Ÿš€ Getting Started #

1. Add Dependency #

In your pubspec.yaml:

dependencies:
  flutter_second_screen: ^1.0.0

2. Main Entry Point Setup #

In your main.dart, handle the secondary screen entry point when the process is launched:

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

void main(List<String> args) async {
  WidgetsFlutterBinding.ensureInitialized();
  await FlutterSecondScreen.ensureInitialized(args);

  if (FlutterSecondScreen.isSecondaryScreen(args)) {
    // Secondary screen process
    final initialized = await FlutterSecondScreen.instance.initSecondaryDisplay(
      const SecondScreenConfig(title: 'Customer Facing Display'),
    );
    if (initialized) {
      runApp(const CustomerDisplayApp());
    }
  } else {
    // Main cashier / POS application
    runApp(const CashierMainApp());
  }
}

๐Ÿ’ก Usage Examples #

Opening the Secondary Screen #

final secondScreen = FlutterSecondScreen.instance;

// Check if a second physical monitor is connected
if (await secondScreen.isSecondaryDisplayAvailable()) {
  await secondScreen.openSecondaryScreen(arguments: ['second-screen']);
}

Sending Events Between Screens #

// Send from Main Screen to Secondary Screen
await secondScreen.sendEventToSecondary('cartUpdate', {
  'items': [
    {'name': 'Sneakers', 'price': 89.99},
  ],
  'total': 89.99,
});

// Send from Secondary Screen back to Main Screen (e.g. Signature or Confirmation)
await secondScreen.sendEventToMain('signatureApproved', signatureData);

Listening to Events with SecondScreenListenerMixin #

class CustomerDisplayScreen extends StatefulWidget {
  const CustomerDisplayScreen({super.key});

  @override
  State<CustomerDisplayScreen> createState() => _CustomerDisplayScreenState();
}

class _CustomerDisplayScreenState extends State<CustomerDisplayScreen>
    with SecondScreenListenerMixin {
  Map<String, dynamic>? cartData;

  @override
  Map<String, void Function(dynamic)> getSecondScreenEventListeners() {
    return {
      'cartUpdate': (data) {
        setState(() {
          cartData = data as Map<String, dynamic>;
        });
      },
      'reset': (_) {
        setState(() {
          cartData = null;
        });
      },
    };
  }

  @override
  Widget build(BuildContext context) {
    if (cartData == null) {
      return const Center(child: Text('Welcome!'));
    }
    return Text('Total: \$${cartData!['total']}');
  }
}

Listening to Events with SecondScreenEventListener Widget #

SecondScreenEventListener(
  eventName: 'cartUpdate',
  onEvent: (data) {
    debugPrint('Received cart update: $data');
  },
  child: const MyCartWidget(),
);

๐Ÿ“ฑ Upcoming Android & iOS Implementation #

flutter_second_screen defines clean platform contracts and architectural blueprints for Android and iOS in:

  • AndroidSecondScreenPlatform (lib/src/data/datasources/android_second_screen_platform.dart)
  • IosSecondScreenPlatform (lib/src/data/datasources/ios_second_screen_platform.dart)

Android Roadmap #

  • Integrates with Android's DisplayManager.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION).
  • Spawns a secondary FlutterEngine inside an android.app.Presentation dialog window.
  • Communicates across engines via native MethodChannel and EventChannel.

iOS Roadmap #

  • Detects external displays via UIScreen.screens and UIScreenDidConnectNotification.
  • Attaches a secondary UIWindow with a FlutterViewController bound to the external UIScreen.
  • Communicates across engines via native MethodChannel and EventChannel.

๐Ÿงช Testing #

The package includes comprehensive unit and widget tests covering all entities, use cases, repository implementations, mixins, and platform interfaces:

flutter test

๐Ÿ“„ License #

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

๐ŸŒŸ Support #

If you find this package helpful, please consider giving it a โญ on GitHub and a ๐Ÿ‘ on pub.dev!

0
likes
160
points
0
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A clean architecture Flutter package for managing secondary screens and cross-screen communication on Windows and macOS desktop, with upcoming Android and iOS support.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter, plugin_platform_interface, screen_retriever, window_manager_plus

More

Packages that depend on flutter_second_screen

Packages that implement flutter_second_screen