A mason brick to create the directory structure and boilerplate to implement a feature leveraging the page-switcher-view pattern

Page View Feature

A brick to create the directory structure and boilerplate to implement a feature leveraging the page-switcher-view pattern.

For more information on this pattern check out this blog.

Note: This brick uses Super Initializers for view widgets. Therefore, make sure you’re using dart 2.17 on your end.

? How to use

mason make page_switcher_view --app_name "cool app" --feature_name whatever

? Variables

Variable Description
app_name Name of the app including the new feature.
feature_name Name of the new feature implementing the Page-Switcher-Pattern

✅ Outputs

Directory Structure

├── whatever
│   ├── bloc
│   │   ├── whatever_bloc.dart
│   │   ├── whatever_event.dart
│   │   └── whatever_state.dart
│   ├── view
|   |   ├── view.dart
│   │   ├── whatever_page.dart
│   │   ├── whatever_switcher.dart
│   │   └── whatever_view.dart
│   ├── widgets
│   │   └── widgets.dart
│   └── whatever.dart
└── ...

Files Content

whatever_bloc.dart

import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';

part 'whatever_event.dart';
part 'whatever_state.dart';

class WhateverBloc extends Bloc<WhateverEvent, WhateverState> {
  WhateverBloc() : super(const WhateverState()) {
    on<WhateverDataRequested>(_dataRequested);
  }

  FutureOr<void> _dataRequested(
    WhateverDataRequested event,
    Emitter<WhateverState> emit,
  ) async {
    emit(state.copyWith(status: WhateverStatus.loading));
    try {
      // TODO(you): INITIAL ASYNC CALL
      emit(state.copyWith(status: WhateverStatus.success));
    } catch (error, stackTrace) {
      addError(error, stackTrace);
      emit(state.copyWith(status: WhateverStatus.error));
    }
  }
}

whatever_event.dart

part of 'whatever_bloc.dart';

abstract class WhateverEvent extends Equatable {
  const WhateverEvent();

  @override
  List<Object> get props => [];
}

class WhateverDataRequested extends WhateverEvent {}

whatever_state.dart

part of 'whatever_bloc.dart';

enum WhateverStatus { initial, loading, success, error }

class WhateverState extends Equatable {
  const WhateverState({this.status = WhateverStatus.initial});

  final WhateverStatus status;

  @override
  List<Object> get props => [status];

  WhateverState copyWith({
    WhateverStatus? status,
  }) {
    return WhateverState(
      status: status ?? this.status,
    );
  }
}

view.dart

export 'whatever_page.dart';
export 'whatever_switcher.dart';
export 'whatever_view.dart';

whatever_page.dart

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:cool_app/whatever/whatever.dart';

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

  static String path = 'whatever';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: BlocProvider(
        create: (context) => WhateverBloc()..add(WhateverDataRequested()),
        child: const WhateverSwitcher(),
      ),
    );
  }
}

whatever_switcher.dart

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:cool_app/whatever/whatever.dart';

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

  @override
  Widget build(BuildContext context) {
    final status = context.select(
      (WhateverBloc bloc) => bloc.state.status,
    );
    switch (status) {
      case WhateverStatus.initial:
      case WhateverStatus.loading:
        // TODO(you): CREATE CUSTOM LOADING VIEW
        return const Center(child: CircularProgressIndicator());
      case WhateverStatus.success:
        return const WhateverView();
      case WhateverStatus.error:
        // TODO(you): CREATE CUSTOM ERROR VIEW
        return Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              const Text('Something went wrong.'),
              const SizedBox(height: 16),
              ElevatedButton(
                onPressed: () {
                  context.read<WhateverBloc>().add(WhateverDataRequested());
                },
                child: const Text('Try again'),
              ),
            ],
          ),
        );
    }
  }
}

whatever_success.dart

import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text('Success'),
    );
  }
}

widgets.dart

export 'bloc/whatever_bloc.dart';
export 'view/view.dart';
export 'widgets/widgets.dart';

GitHub

View Github