noob 0.0.8 copy "noob: ^0.0.8" to clipboard
noob: ^0.0.8 copied to clipboard

A few handy Flutter tools, dead simple `UriRouter` for `Uri`-based navigator or `BuildTracker` to track widget rebuilds and what caused them to rebuild.

example/lib/main.dart

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:noob/noob.dart';

// initialize `BuildTracker`
final buildTracker = BuildTracker(
  printBuildFrameIncludeRebuildDirtyWidget: false,
  enabled: false,
) //
  ..addIgnored([
    '_FocusMarker',
    'FocusScope',
    'Focus',
    '_MaterialInterior',
    'RawMaterialButton',
    'UncontrolledProviderScope ← ProviderScope',
    "Consumer-[<'PositionIndicator'>]",
    "HookBuilder-[<'ignore'>]",
  ]);

void main() {
  // initialize `TrackingBuildOwnerWidgetsFlutterBinding` to enable tracking
  TrackingBuildOwnerWidgetsFlutterBinding.ensureInitialized();

  // print top 10 stacks leading to rebuilds every 10 seconds
  Timer.periodic(
    const Duration(seconds: 10),
    (_) => buildTracker.printTopScheduleBuildForStacks(),
  );

  final router = UriRouter(
    routes: [
      MyHomePage.route,
      PointerIndicatorExample.route,
      BuildTrackerExample.route,
      BooksPage.route,
    ],
  );

  runApp(
    ProviderScope(
      child: MyApp(
        router: router,
      ),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({
    Key? key,
    required this.router,
  }) : super(key: key);

  final UriRouter router;

  @override
  Widget build(BuildContext context) => MaterialApp(
        title: 'noob',
        theme: ThemeData(primarySwatch: Colors.blue),
        onGenerateRoute: router.generateRoute,
      );
}

class MyHomePage extends HookWidget {
  static final route = UriRoute.widget(path: '/', child: const MyHomePage());
  static final path = route.build();

  const MyHomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(title: const Text('noob examples')),
        body: ListView(
          children: [
            Card(
              child: InkWell(
                onTap: () =>
                    Navigator.pushNamed(context, PointerIndicatorExample.path),
                child: const ListTile(
                  title: Text(
                    'PointerIndicator',
                  ),
                ),
              ),
            ),
            Card(
              child: InkWell(
                onTap: () =>
                    Navigator.pushNamed(context, BuildTrackerExample.path),
                child: const ListTile(
                  title: Text(
                    'BuildTracker',
                  ),
                ),
              ),
            ),
            Card(
              child: InkWell(
                onTap: () => Navigator.pushNamed(context, BooksPage.path('1')),
                child: const ListTile(
                  title: Text(
                    'UriRouter -> Book 1',
                  ),
                ),
              ),
            ),
          ],
        ),
      );
}

class PointerIndicatorExample extends HookWidget {
  static final route = UriRoute.widget(
    path: 'PointerIndicator',
    child: const PointerIndicatorExample(),
  );
  static final path = route.build();

  const PointerIndicatorExample({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(title: const Text('PointerIndicator')),
        body: PointerIndicator(
          child: ListView.builder(
            itemBuilder: (_, i) => Card(
              child: ListTile(
                title: Text('Item $i'),
              ),
            ),
          ),
        ),
      );
}

final counterProvider = StateProvider((ref) => 0);

class BuildTrackerExample extends HookConsumerWidget {
  static final route =
      UriRoute.widget(path: 'BuildTracker', child: const BuildTrackerExample());
  static final path = route.build();

  const BuildTrackerExample({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final log = useValueNotifier('');
    useEffect(() {
      buildTracker.enabled = true;
      final savedDebugPrint = debugPrint;
      debugPrint = (String? message, {int? wrapWidth}) {
        savedDebugPrint(message, wrapWidth: wrapWidth);
        log.value += '$message\n';
      };
      return () {
        buildTracker.enabled = false;
        debugPrint = savedDebugPrint;
      };
    });
    final counter = ref.watch(counterProvider);
    return Scaffold(
      appBar: AppBar(title: const Text('BuildTracker')),
      body: Align(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Text('Button clicked $counter times'),
            const Text('debugPrint output:'),
            Expanded(
              child: HookBuilder(
                key: const ValueKey('ignore'),
                builder: (_) {
                  final controller = useScrollController();
                  WidgetsBinding.instance.addPostFrameCallback(
                    (_) =>
                        controller.jumpTo(controller.position.maxScrollExtent),
                  );
                  return Markdown(
                    data: useValueListenable(log),
                    controller: controller,
                  );
                },
              ),
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => ref.read(counterProvider.notifier).state++,
        child: const Icon(Icons.add),
      ),
    );
  }
}

class BooksPage extends StatelessWidget {
  static final route = UriRoute(
    path: '/books/:id',
    pageBuilder: (context, params) => BooksPage(
      id: params.pathParams['id']!,
      pageParams: params,
    ),
  );

  static String path(String id) =>
      route.build(pathParams: <String, String>{'id': id});

  const BooksPage({Key? key, required this.pageParams, required this.id})
      : super(key: key);

  final String id;
  final PageParams pageParams;

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(title: Text('UriRouter: BooksPage $id')),
        body: Align(
          child: Text(
            'You selected book $id. Full params:\n$pageParams',
            maxLines: 20,
          ),
        ),
      );
}
9
likes
80
pub points
58%
popularity

Publisher

unverified uploader

A few handy Flutter tools, dead simple `UriRouter` for `Uri`-based navigator or `BuildTracker` to track widget rebuilds and what caused them to rebuild.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (LICENSE)

Dependencies

built_collection, collection, flutter, flutter_hooks, flutter_test, freezed_annotation, hooks_riverpod, stack_trace

More

Packages that depend on noob