PlugFox / flutter-plus

VS Code Extension for Flutter
https://marketplace.visualstudio.com/items?itemName=plugfox.flutter-plus
MIT License
14 stars 2 forks source link

Feature/sealed states #7

Closed PlugFox closed 3 months ago

PlugFox commented 3 months ago
import 'package:meta/meta.dart';

/// Entity placeholder
typedef MyBoringStateEntity = Object;

/// {@template my_boring_state}
/// MyBoringState.
/// {@endtemplate}
sealed class MyBoringState extends _$MyBoringStateBase {
  /// {@macro my_boring_state}
  const MyBoringState({required super.data, required super.message});

  /// Idle
  /// {@macro my_boring_state}
  const factory MyBoringState.idle({
    MyBoringStateEntity? data,
    String message,
  }) = MyBoringState$Idle;

  /// Processing
  /// {@macro my_boring_state}
  const factory MyBoringState.processing({
    MyBoringStateEntity? data,
    String message,
  }) = MyBoringState$Processing;

  /// Succeeded
  /// {@macro my_boring_state}
  const factory MyBoringState.succeeded({
    MyBoringStateEntity? data,
    String message,
  }) = MyBoringState$Succeeded;

  /// Failed
  /// {@macro my_boring_state}
  const factory MyBoringState.failed({
    MyBoringStateEntity? data,
    String message,
  }) = MyBoringState$Failed;

  /// Initial
  /// {@macro my_boring_state}
  factory MyBoringState.initial({
    MyBoringStateEntity? data,
    String? message,
  }) =>
      MyBoringState$Idle(
        data: data,
        message: message ?? 'Initial',
      );
}

/// Idle
final class MyBoringState$Idle extends MyBoringState {
  const MyBoringState$Idle({super.data, super.message = 'Idle'});

  @override
  String get type => 'idle';
}

/// Processing
final class MyBoringState$Processing extends MyBoringState {
  const MyBoringState$Processing({super.data, super.message = 'Processing'});

  @override
  String get type => 'processing';
}

/// Succeeded
final class MyBoringState$Succeeded extends MyBoringState {
  const MyBoringState$Succeeded({super.data, super.message = 'Succeeded'});

  @override
  String get type => 'succeeded';
}

/// Failed
final class MyBoringState$Failed extends MyBoringState {
  const MyBoringState$Failed({super.data, super.message = 'Failed'});

  @override
  String get type => 'failed';
}

/// Pattern matching for [MyBoringState].
typedef MyBoringStateMatch<R, S extends MyBoringState> = R Function(S element);

@immutable
abstract base class _$MyBoringStateBase {
  const _$MyBoringStateBase({required this.data, required this.message});

  /// Type alias for [MyBoringState].
  abstract final String type;

  /// Data entity payload.
  @nonVirtual
  final MyBoringStateEntity? data;

  /// Message or description.
  @nonVirtual
  final String message;

  /// Has data?
  bool get hasData => data != null;

  /// Check if is Idle.
  bool get isIdle => this is MyBoringState$Idle;

  /// Check if is Processing.
  bool get isProcessing => this is MyBoringState$Processing;

  /// Check if is Succeeded.
  bool get isSucceeded => this is MyBoringState$Succeeded;

  /// Check if is Failed.
  bool get isFailed => this is MyBoringState$Failed;

  /// Pattern matching for [MyBoringState].
  R map<R>({
    required MyBoringStateMatch<R, MyBoringState$Idle> idle,
    required MyBoringStateMatch<R, MyBoringState$Processing> processing,
    required MyBoringStateMatch<R, MyBoringState$Succeeded> succeeded,
    required MyBoringStateMatch<R, MyBoringState$Failed> failed,
  }) =>
      switch (this) {
        MyBoringState$Idle s => idle(s),
        MyBoringState$Processing s => processing(s),
        MyBoringState$Succeeded s => succeeded(s),
        MyBoringState$Failed s => failed(s),
        _ => throw AssertionError(),
      };

  /// Pattern matching for [MyBoringState].
  R maybeMap<R>({
    required R Function() orElse,
    MyBoringStateMatch<R, MyBoringState$Idle>? idle,
    MyBoringStateMatch<R, MyBoringState$Processing>? processing,
    MyBoringStateMatch<R, MyBoringState$Succeeded>? succeeded,
    MyBoringStateMatch<R, MyBoringState$Failed>? failed,
  }) =>
      map<R>(
        idle: idle ?? (_) => orElse(),
        processing: processing ?? (_) => orElse(),
        succeeded: succeeded ?? (_) => orElse(),
        failed: failed ?? (_) => orElse(),
      );

  /// Pattern matching for [MyBoringState].
  R? mapOrNull<R>({
    MyBoringStateMatch<R, MyBoringState$Idle>? idle,
    MyBoringStateMatch<R, MyBoringState$Processing>? processing,
    MyBoringStateMatch<R, MyBoringState$Succeeded>? succeeded,
    MyBoringStateMatch<R, MyBoringState$Failed>? failed,
  }) =>
      map<R?>(
        idle: idle ?? (_) => null,
        processing: processing ?? (_) => null,
        succeeded: succeeded ?? (_) => null,
        failed: failed ?? (_) => null,
      );

  @override
  int get hashCode => Object.hash(type, data);

  @override
  bool operator ==(Object other) => identical(this, other)
   || (other is _$MyBoringStateBase && type == other.type && identical(data, other.data));

  @override
  String toString() => 'MyBoringState.$type{message: $message}';
}